Lezioni del modulo (3/5)
Benchmark e profili
Oltre ai test funzionali, go test integra anche benchmark (BenchmarkXxx) e supporta i profili (pprof) di CPU e memoria. Tutto senza dipendenze esterne.
Forma di un benchmark
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Sum(2, 3)
}
}Caratteristiche:
- Firma esatta:
func BenchmarkXxx(b *testing.B). - Il loop deve eseguire
b.Niterazioni: il framework regolab.Nautomaticamente, partendo da 1 e crescendo fino a stabilizzare la misura (~1 secondo per default). - Il risultato è
ns/op(nanosecondi per operazione) e, con-benchmem, ancheB/opeallocs/op.
Comandi tipici
go test -bench=. ./... # tutti i benchmark
go test -bench=Sum -benchmem # solo Sum, con info su memoria
go test -bench=. -benchtime=5s # ogni benchmark per 5 secondi
go test -bench=. -cpuprofile=cpu.out # genera profilo CPUL'output tipico:
BenchmarkSum-8 1000000000 0.31 ns/op
-8 è il valore di GOMAXPROCS. 0.31 ns/op è il tempo medio per chiamata.
Setup costoso: b.ResetTimer
Se prima del loop hai una preparazione lunga, escludila dalla misura:
func BenchmarkSearch(b *testing.B) {
data := buildLargeSlice(1_000_000) // costoso
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = Search(data, 42)
}
}Varianti utili:
b.StopTimer()/b.StartTimer()— pausa la misura intorno a una fase non interessante (utile dentro al loop).b.ReportAllocs()— forza la stampa di allocazioni anche senza-benchmem.
Tabella di benchmark con b.Run
Come t.Run per i test, esiste b.Run per benchmark parametrici:
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, ",")
}
})
}
}Output con righe BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... ideale per grafici di scaling.
Confrontare due implementazioni con benchstat
go test -bench=. -count=10 > old.txt
# applica modifica
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txtbenchstat (in golang.org/x/perf/cmd/benchstat) calcola media, deviazione standard e significatività statistica della differenza.
Esercizi
Definisci BenchmarkSum con il loop su b.N che chiama Sum(2, 3).
Soluzione disponibile dopo 3 tentativi
Aggiungi b.ResetTimer DOPO il setup costoso, prima del loop, in modo che il setup non sia incluso nella misura.
Soluzione disponibile dopo 3 tentativi
Quale flag esegue tutti i benchmark del package?
$ go test ???