patterngoTip
Benchmarking Go code with testing.B
Viewed 0 times
benchmarktesting.Bgo test -benchbenchmemallocs per opperformance testingb.N
Problem
Ad-hoc timing with time.Now() is inaccurate for micro-benchmarks because it does not account for loop overhead, compiler optimisations, or GC pauses.
Solution
Use the built-in benchmarking framework:
Prevent dead-code elimination:
func BenchmarkMyFunc(b *testing.B) {
// Setup outside the loop
data := generateTestData()
b.ResetTimer() // reset timer after setup
for i := 0; i < b.N; i++ {
MyFunc(data)
}
}
// Run
go test -bench=. -benchmem ./...
// -benchmem shows allocations per op
// -benchtime=5s runs for 5 seconds instead of default 1s
// -count=3 runs benchmark 3 times for stabilityPrevent dead-code elimination:
var result int
func BenchmarkMyFunc(b *testing.B) {
var r int
for i := 0; i < b.N; i++ {
r = MyFunc(i)
}
result = r // assign to package-level var
}Why
testing.B runs the function b.N times, adjusting N until results are statistically stable. -benchmem instruments the allocator to report bytes/op and allocs/op, critical for spotting unnecessary heap allocations.
Gotchas
- The compiler may optimise away function calls whose results are unused — store results in a package-level variable
- b.ResetTimer() is necessary when setup is expensive; otherwise setup time pollutes the benchmark
- Benchmarks in a _test.go file run in the same process — isolate OS-level benchmarks with a separate binary
Revisions (0)
No revisions yet.