Przejdź do głównej treści
eLearner.app
Moduł 9 · Lekcja 3 z 543/50 w kursie~12 min
Lekcje modułu (3/5)

Benchmarki i profile

Oprócz testów funkcjonalnych, go test ma również wbudowane testy porównawcze (BenchmarkXxx) i obsługuje profile procesora i pamięci (pprof). Wszystko bez zewnętrznych zależności.

Kształt benchmarku

Go
func BenchmarkSum(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = Sum(2, 3)
    }
}

Charakterystyka:

  • Dokładny podpis: func BenchmarkXxx(b *testing.B).
  • Pętla musi wykonywać iteracje b.N: struktura automatycznie dostosowuje b.N, zaczynając od 1 i rosnąc, aż pomiar się ustabilizuje (domyślnie ~ 1 sekunda).
  • Wynikiem jest ns/op (nanosekundy na operację), a w przypadku -benchmem także B/op i allocs/op.

Typowe polecenia

Bash
go test -bench=. ./...              # all benchmarks
go test -bench=Sum -benchmem        # only Sum, with memory info
go test -bench=. -benchtime=5s      # each benchmark for 5 seconds
go test -bench=. -cpuprofile=cpu.out # generate a CPU profile

Typowe wyjście:

Code
BenchmarkSum-8        1000000000        0.31 ns/op

-8 jest wartością GOMAXPROCS. 0.31 ns/op to średni czas połączenia.

Kosztowna konfiguracja: b.ResetTimer

Jeśli przed pętlą masz długi etap przygotowawczy, wyklucz ją z pomiaru:

Go
func BenchmarkSearch(b *testing.B) {
    data := buildLargeSlice(1_000_000) // expensive
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        _ = Search(data, 42)
    }
}

Przydatne warianty:

  • b.StopTimer() / b.StartTimer() — pauza pomiaru wokół nieciekawej fazy (przydatne w pętli).
  • b.ReportAllocs() — raportowanie alokacji siły nawet bez -benchmem.

Tabela porównawcza z b.Run

Podobnie jak t.Run do testów, istnieje b.Run do testów parametrycznych:

Go
func BenchmarkSplit(b *testing.B) {
    for _, size := range []int{10, 1000, 100000} {
        b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) {
            s := strings.Repeat("a,", size)
            b.ResetTimer()
            for i := 0; i < b.N; i++ {
                _ = strings.Split(s, ",")
            }
        })
    }
}

Wiersze wyjściowe, takie jak BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... idealne do wykresów skalujących.

Porównanie dwóch implementacji z benchstat

Bash
go test -bench=. -count=10 > old.txt
# apply change
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txt

benchstat (w golang.org/x/perf/cmd/benchstat) oblicza średnią, odchylenie standardowe i istotność statystyczną różnicy.

Ćwiczenia

Ćwiczenie#go.m9.l3.e1
Próby: 0Ładowanie...

Zdefiniuj BenchmarkSum za pomocą pętli nad b.N, która wywołuje Sum(2, 3).

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m9.l3.e2
Próby: 0Ładowanie...

Dodaj b.ResetTimer PO drogiej konfiguracji, przed pętlą, aby konfiguracja nie została uwzględniona w pomiarze.

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Quiz#go.m9.l3.e3
Gotowe

Która flaga obsługuje wszystkie testy porównawcze w pakiecie?

Go
$ go test ???
Opcje odpowiedzi