Lektionen des Moduls (3/5)
Benchmarks und Profile
Neben Funktionstests verfügt go test auch über integrierte Benchmarks (BenchmarkXxx) und unterstützt CPU- und Speicherprofile (pprof). Alles ohne externe Abhängigkeiten.
Form einer Benchmark
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Sum(2, 3)
}
}Eigenschaften:
- Genaue Signatur:
func BenchmarkXxx(b *testing.B). – Die Schleife mussb.N-Iterationen ausführen: Das Framework passtb.Nautomatisch an, beginnend bei 1 und ansteigend, bis sich die Messung stabilisiert (standardmäßig ~1 Sekunde). - Das Ergebnis ist
ns/op(Nanosekunden pro Operation) und mit-benchmemauchB/opundallocs/op.
Typische Befehle
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 profileTypische Ausgabe:
BenchmarkSum-8 1000000000 0.31 ns/op
-8 ist der GOMAXPROCS-Wert. 0.31 ns/op ist die durchschnittliche Zeit pro Anruf.
Teures Setup: b.ResetTimer
Wenn Sie vor der Schleife einen langen Vorbereitungsschritt haben, schließen Sie ihn von der Messung aus:
func BenchmarkSearch(b *testing.B) {
data := buildLargeSlice(1_000_000) // expensive
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = Search(data, 42)
}
}Nützliche Varianten:
b.StopTimer()/b.StartTimer()– Pausieren Sie die Messung um eine uninteressante Phase herum (praktisch innerhalb der Schleife).b.ReportAllocs()– Zuordnungsberichterstattung auch ohne-benchmemerzwingen.
Benchmark-Tabelle mit b.Run
Genau wie t.Run für Tests gibt es b.Run für parametrische Benchmarks:
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, ",")
}
})
}
}Ausgabezeilen wie BenchmarkSplit/n=10-8, BenchmarkSplit/n=1000-8, ... ideal zum Skalieren von Diagrammen.
Vergleich zweier Implementierungen mit benchstat
go test -bench=. -count=10 > old.txt
# apply change
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txtbenchstat (in golang.org/x/perf/cmd/benchstat) berechnet den Mittelwert, die Standardabweichung und die statistische Signifikanz der Differenz.
Übungen
Definieren Sie BenchmarkSum mit der Schleife über b.N, die Sum(2, 3) aufruft.
Lösung nach 3 Versuchen verfügbar
Fügen Sie b.ResetTimer NACH dem teuren Setup vor der Schleife hinzu, damit das Setup nicht in die Messung einbezogen wird.
Lösung nach 3 Versuchen verfügbar
Welches Flag führt alle Benchmarks im Paket aus?
$ go test ???