testing.B.Loop is the preferred Go benchmark loop introduced in Go 1.24. It repeatedly executes the code being measured while preventing compiler optimizations from silently removing the calls. The loop continues while b.Loop() returns true; by default, benchmarking runs for about one second. section 3.2.1 section 3.3.3
Benchmarking a String method
func BenchmarkURLString(b *testing.B) { u := &URL{ Scheme: "https", Host: "github.com", Path: "inancgumus", } for b.Loop() { _ = u.String() } } Run it with `go test ./url -bench=. -benchmem`. The output reports metrics such as ns/op, B/op, and allocs/op. Place setup outside the loop so the measurements focus on String rather than constructing the URL. section 3.2.1
Use Loop to avoid common benchmark mistakes:
- Prefer `for b.Loop()` over the classical `for range b.N` form when writing new benchmarks. section 3.3 section 3.3.3
- Do not combine `b.N` and `b.Loop()` in one benchmark; use the newer loop consistently. section 3.3.3
- Keep setup and cleanup outside the loop when they are not part of the operation being measured. section 3.3.3
- Use `-benchtime`, such as `-benchtime=2s`, when a longer measurement window is useful. section 3.2.1
Why loop placement changes results
func BenchmarkMemoryFast(b *testing.B) { image := make([]byte, 1_000_000) for b.Loop() { resize(image) } } func BenchmarkMemorySlow(b *testing.B) { for b.Loop() { image := make([]byte, 1_000_000) resize(image) } } The first benchmark measures resize with one allocation before measurement; the second includes a one-million-byte allocation in every operation.
func BenchmarkPow(b *testing.B) { for b.Loop() { Pow(5, 1) #1 } }
Inspect the compact Pow benchmark that replaces b.N with b.Loop(). section 3.3.3
