Salt la conținutul principal
Modulul 9 · Lecția 3 din 543/50 în curs~12 min
Lecții din modul (3/5)

Benchmark-uri și profile

Pe lângă testele funcționale, go test are și benchmarks (BenchmarkXxx) și acceptă profilele CPU și memorie (pprof). Toate fără dependențe externe.

Forma unui reper

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

Caracteristici:

  • Semnătură exactă: func BenchmarkXxx(b *testing.B).
  • Bucla trebuie să ruleze b.N iterații: cadrul ajustează b.N automat, începând de la 1 și crescând până când măsurarea se stabilizează (~1 secundă în mod implicit).
  • Rezultatul este ns/op (nanosecunde per operație) și, cu -benchmem, de asemenea B/op și allocs/op.

Comenzi tipice

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

Ieșire tipică:

Code
BenchmarkSum-8        1000000000        0.31 ns/op

-8 este valoarea GOMAXPROCS. 0.31 ns/op este durata medie per apel.

Configurare costisitoare: b.ResetTimer

Dacă aveți un pas lung de pregătire înainte de buclă, excludeți-l din măsurare:

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

Variante utile:

  • b.StopTimer() / b.StartTimer() — întrerupeți măsurarea în jurul unei faze neinteresante (utilă în interiorul buclei).
  • b.ReportAllocs() — forțați raportarea alocării chiar și fără -benchmem.

Tabel de referință cu b.Run

La fel ca t.Run pentru teste, există b.Run pentru benchmark-urile parametrice:

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, ",")
            }
        })
    }
}

Rânduri de ieșire precum BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... ideale pentru scalarea diagramelor.

Compararea a două implementări cu benchstat

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

benchstat (în golang.org/x/perf/cmd/benchstat) calculează media, abaterea standard și semnificația statistică a diferenței.

Exerciții

Exercițiu#go.m9.l3.e1
Încercări: 0Se încarcă…

Definiți BenchmarkSum cu bucla peste b.N care apelează Sum(2, 3).

Se încarcă editorul...

Soluție disponibilă după 3 încercări

Exercițiu#go.m9.l3.e2
Încercări: 0Se încarcă…

Adăugați b.ResetTimer DUPĂ configurarea costisitoare, înainte de buclă, astfel încât configurarea nu este inclusă în măsurare.

Se încarcă editorul...

Soluție disponibilă după 3 încercări

Quiz#go.m9.l3.e3
Gata

Care steag rulează toate benchmark-urile din pachet?

Go
$ go test ???
Opțiuni de răspuns