Профилирование и оптимизация программ на Go

Профилирование и оптимизация программ на Go

Доклад на конференции Стачка 2017

4618c5e97c59abd315cc2d7dc809f8c8?s=128

Alexey Palazhchenko

April 14, 2017
Tweet

Transcript

  1. Профилирование и оптимизация программ на Go Алексей Палажченко 14 апреля

    2017, Стачка
  2. Профилирование и оптимизация программ на Go Алексей Палажченко 14 апреля

    2017, Стачка
  3. None
  4. None
  5. None
  6. None
  7. None
  8. None
  9. type Cache interface { Get(id string) interface{} Set(id string, value

    interface{}) Len() int }
  10. func (s *Slice) Get(id string) interface{} { for _, it

    := range s.items { if it.id == id { return it.value } } return nil }
  11. func (s *Slice) Set(id string, value i{}) { for i,

    it := range s.items { if it.id == id { s.items[i].value = value return } } s.items = append(s.items, item{id, value}) }
  12. func (s *Slice) Set(id string, value i{}) { for i,

    it := range s.items { if it.id == id { s.items[i].value = value return } } s.items = append(s.items, item{id, value}) }
  13. b.ResetTimer() for i := 0; i < b.N; i++ {

    for _, id := range ids { Sink = c.Get(id) } }
  14. 100 200 300 400 0 1 2 3 4 5

    6 7 8 9 10 Slice Map
  15. 100 200 300 400 0 1 2 3 4 5

    6 7 8 9 10 Slice Map Fancy algorithms are slow when n is small, and n is usually small. - Rob Pike
  16. Sink func popcnt(x uint64) int { var res uint64 for

    ; x > 0; x >>= 1 { res += x & 1 } return int(res) }
  17. Sink const m1 = 0x5555555555555555 const m2 = 0x3333333333333333 const

    m4 = 0x0f0f0f0f0f0f0f0f const h01 = 0x0101010101010101 func popcnt2(x uint64) int { x -= (x >> 1) & m1 x = (x & m2) + ((x >> 2) & m2) x = (x + (x >> 4)) & m4 return int((x * h01) >> 56) }
  18. Sink func BenchmarkPopcnt(b *testing.B) { for i := 0; i

    < b.N; i++ { popcnt(uint64(i)) } } func BenchmarkPopcnt2(b *testing.B) { for i := 0; i < b.N; i++ { popcnt2(uint64(i)) } }
  19. Sink go test -v -bench=. BenchmarkPopcnt-4 100000000 15.5 ns/op BenchmarkPopcnt2-4

    2000000000 0.34 ns/op
  20. Sink go test -v -bench=. BenchmarkPopcnt-4 100000000 15.5 ns/op BenchmarkPopcnt2-4

    2000000000 0.34 ns/op
  21. Sink • go doc compile • go test -bench=. -gcflags

    "-S"
  22. Sink popcnt_test.go:14 MOVQ "".b+8(FP), AX popcnt_test.go:14 MOVQ $0, CX popcnt_test.go:14

    MOVQ 200(AX), DX popcnt_test.go:14 CMPQ CX, DX popcnt_test.go:14 JGE $0, 34 popcnt_test.go:14 INCQ CX popcnt_test.go:14 MOVQ 200(AX), DX popcnt_test.go:14 CMPQ CX, DX popcnt_test.go:14 JLT $0, 19 popcnt_test.go:17 RET
  23. Sink func BenchmarkPopcnt(b *testing.B) { for i := 0; i

    < b.N; i++ { Sink = popcnt(uint64(i)) } } func BenchmarkPopcnt2(b *testing.B) { for i := 0; i < b.N; i++ { Sink = popcnt2(uint64(i)) } }
  24. Sink go test -v -bench=. BenchmarkPopcnt-4 50000000 39.3 ns/op BenchmarkPopcnt2-4

    50000000 26.8 ns/op
  25. Sink env GOSSAFUNC=BenchmarkPopcnt2 go test -bench=.

  26. Benchmarks • Не в виртуальной машине • Не трогать во

    время работы • Выключить автоматическое управление питанием • rsc.io/benchstat
  27. pprof • runtime/pprof • net/http/pprof • go test • Не

    больше одного за раз!
  28. pprof: CPU • setitimer(2), ITIMER_PROF, SIGPROF • До 500 Гц

    (100 по умолчанию) • SetCPUProfileRate(hz) • go test -bench=XXX -cpuprofile=XXX.pprof • go tool pprof -svg -output=XXX.svg cache.test XXX.pprof
  29. None
  30. None
  31. pprof: mem/block/mutex • pprof.MemProfileRate = bytes • pprof.SetBlockProfileRate(ns) • pprof.SetMutexProfileFraction(rate)

  32. type Map struct { m sync.Mutex items map[string]interface{} } func

    (m *Map) Get(id string) interface{} { m.m.Lock() defer m.m.Unlock() return m.items[id] }
  33. pprof: block • go test -v -bench=XXX -blockprofile=XXX.pprof • go

    tool pprof -svg -lines -output=XXX.svg ccache.test XXX.pprof
  34. None
  35. type Map struct { m sync.RWMutex items map[string]interface{} } func

    (m *Map) Get(id string) interface{} { m.m.RLock() v := m.items[id] m.m.RUnlock() return v }
  36. pprof: свои профили • Когда нужны stack traces • Интеграция

    с go tool pprof • Пример: открытие и закрытие файлов • pprof.NewProfile, pprof.Lookup • Profile.Add, Remove
  37. Execution tracer • Запуск, остановка, переключение горутин • Блокировки на

    каналах, select • Блокировки на mutex’ах • Блокировки на сети, syscall’ах
  38. Execution tracer • Все события с полным контекстом • Большие

    файлы (со всеми символами) • Замедление ~25% • pprof CPU для throughput, tracer для latency
  39. Execution tracer • import _ "net/http/pprof" • http://127.0.0.1:8080/debug/pprof • redis-benchmark

    -r 100000 -e -l -t set,get • go tool trace trace.out
  40. Execution tracer • go tool trace -pprof=TYPE trace.out > TYPE.pprof

    • net • sync • syscall • sched
  41. Linux • perf (perf_events) • SystemTap • BPF (eBPF)

  42. Переменные окружения • GOGC (100, off) • GODEBUG • gctrace=1

    • allocfreetrace=1 • schedtrace=1000
  43. Оптимизации • struct{} • m[string(b)] • for i, c :=

    range []byte(s) • for i := range s { a[i] = <zero value> }
  44. Оптимизации type Key [64]byte type Value struct { Name [32]byte

    Balance uint64 Timestamp int64 } m := make(map[Key]Value, 1e8)
  45. • golang-ru @ Google Groups • 4gophers.ru/slack • golangshow.com •

    github.com/AlekSi/ stachka-2017