Vai al contenuto
eLearner.app
Modulo 9 · Lezione 3 di 543/50 nel corso~12 min
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

Go
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.N iterazioni: il framework regola b.N automaticamente, partendo da 1 e crescendo fino a stabilizzare la misura (~1 secondo per default).
  • Il risultato è ns/op (nanosecondi per operazione) e, con -benchmem, anche B/op e allocs/op.

Comandi tipici

Bash
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 CPU

L'output tipico:

Code
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:

Go
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:

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

Output con righe BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... ideale per grafici di scaling.

Confrontare due implementazioni con benchstat

Bash
go test -bench=. -count=10 > old.txt
# applica modifica
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txt

benchstat (in golang.org/x/perf/cmd/benchstat) calcola media, deviazione standard e significatività statistica della differenza.

Esercizi

Esercizio#go.m9.l3.e1
Tentativi: 0Caricamento…

Definisci BenchmarkSum con il loop su b.N che chiama Sum(2, 3).

Caricamento editor…

Soluzione disponibile dopo 3 tentativi

Esercizio#go.m9.l3.e2
Tentativi: 0Caricamento…

Aggiungi b.ResetTimer DOPO il setup costoso, prima del loop, in modo che il setup non sia incluso nella misura.

Caricamento editor…

Soluzione disponibile dopo 3 tentativi

Quiz#go.m9.l3.e3
Pronto

Quale flag esegue tutti i benchmark del package?

Go
$ go test ???
Opzioni di risposta