Skip to content

Benchmarks

A benchmark measures how long a piece of code takes to run. Go benchmarks live in _test.go files alongside unit tests and are run by the same go test command — just with different flags.

A benchmark function has this signature:

func BenchmarkXxx(b *testing.B) {
// ... setup code (not measured) ...
for b.Loop() { // Go 1.24+ preferred form
// code under measurement
}
}

The testing.B value drives the loop. The framework starts with a small value for b.N and keeps increasing it until the benchmark runs long enough to produce a stable measurement. You never set b.N yourself.

Go 1.24 introduced b.Loop() as the preferred alternative to the classic b.N counter loop:

// Classic form — works in all Go versions
func BenchmarkFibClassic(b *testing.B) {
for i := 0; i < b.N; i++ {
Fibonacci(20)
}
}
// Modern form — Go 1.24+
func BenchmarkFib(b *testing.B) {
for b.Loop() {
Fibonacci(20)
}
}

Both forms are correct. b.Loop() is preferred in Go 1.24+ because it handles timer reset internally and is less error-prone.

If your benchmark needs expensive setup (opening a file, building a large slice), do it before the loop and call b.ResetTimer() so setup time is not counted:

func BenchmarkIsPrimeList(b *testing.B) {
numbers := make([]int, 1000)
for i := range numbers {
numbers[i] = i + 2
}
b.ResetTimer() // start measuring from here
for b.Loop() {
for _, n := range numbers {
IsPrime(n)
}
}
}

Unit tests do not run benchmarks by default. Use the -bench flag:

Terminal window
# Run all benchmarks, show memory allocations
go test -bench=. -benchmem ./...
# Run only benchmarks matching a name pattern
go test -bench=BenchmarkFib -benchmem ./...
# Run benchmarks for at least 5 seconds per function
go test -bench=. -benchtime=5s ./...
BenchmarkFib-8 5000000 234 ns/op
BenchmarkFibClassic-8 5000000 236 ns/op 0 B/op 0 allocs/op
ColumnMeaning
-8 suffixGOMAXPROCS value (8 logical CPUs)
5000000Number of iterations b.N ran
234 ns/opNanoseconds per operation
0 B/opBytes allocated per operation (needs -benchmem)
0 allocs/opHeap allocations per operation (needs -benchmem)

Fibonacci allocates nothing because it uses only stack variables — that is why both alloc columns are zero. A function that builds a []string would show non-zero values.

What does the testing framework do with b.N during a benchmark run?
Which flag makes go test report bytes allocated per operation?
When should you call b.ResetTimer() in a benchmark?
What is the preferred benchmark loop form in Go 1.24+?