Appendix D. Benchmarking
Go’s built-in benchmarking support makes it straightforward to measure execution time and memory usage in a way that mirrors unit tests. Benchmarks use the testing package’s B type, whose N field controls how many iterations are run to produce stable results; you do not set N yourself. Functions intended for benchmarking follow the naming convention of starting with Benchmark and are executed by the go test tool with special flags.
To illustrate, the text compares two ways of building strings for a feedback value in a word game: repeated string concatenation versus using a strings.Builder. Readers are encouraged to extend the benchmarks to more realistic lengths (such as five characters). The benchmarks are run with go test using options to select benchmarks, skip regular tests if desired, and include memory statistics (for example, -run=^$, -bench=., and -benchmem).
The benchmark output lists one line per benchmark and includes columns for the function name (with a CPU-related suffix), the iteration count (b.N), time per operation, bytes allocated per operation, and allocations per operation. The tool balances total run time across benchmarks, which is why iteration counts differ but time budgets are comparable. The results show that concatenation is three to four times slower for multiple appends and triggers allocations proportional to the number of concatenations, whereas strings.Builder performs fewer, lighter allocations and runs faster—confirming it as the preferred approach for building strings in this scenario.
D.2 Summary
In order to compare the relative efficiency of two implementations, Go’s test tool allows for a simple implementation of benchmark functions. A BenchmarkNameOfFunc(b *testing.B) function will be considered as a benchmarking function and will be run with go test ./... -run=NameOfFunc -bench=. -benchmem. The benchmarked function must be called inside a for n := 0; n < b.N; n++ { loop.
FAQ
What is the purpose of Go benchmarks, and how are they similar to tests?
Benchmarks measure execution time and memory usage of code paths. They are written much like tests, live in *_test.go files, and use the testing package, but they loop over b.N to run the operation many times.What is testing.B and what does its N field do?
testing.B is the benchmark harness passed to each benchmark function. Its field N is the iteration count; the framework automatically chooses and adjusts it so results are stable. Your benchmark should loop from 0 to b.N.How do I define a benchmark function in Go?
Name it with the prefixBenchmark and the signature func(b *testing.B). Put any one-time setup outside the loop, then run the operation under test inside for i := 0; i < b.N; i++ { ... }.How do I run only benchmarks and include memory statistics?
Usego test ./... -run=^$ -bench=. -benchmem. The -run=^$ regex skips normal tests, -bench=. selects all benchmarks, and -benchmem adds allocation metrics.What do the columns in the benchmark output mean?
- Benchmark name (with a suffix indicating CPU count)- Iterations executed (
b.N)- Time per operation (e.g., ns/op)
- Bytes allocated per operation (B/op)
- Allocations per operation (allocs/op)
What does the suffix like “-10” after a benchmark name indicate?
It shows the number of logical CPUs used when running the benchmark (often equal toGOMAXPROCS).Why is using strings.Builder typically faster than repeated string concatenation?
Strings are immutable, so concatenation creates new strings and triggers multiple allocations proportional to the number of appends.strings.Builder grows an internal buffer, reducing allocations and time per operation.How can I benchmark different input sizes (e.g., building strings of length 5)?
Create additional benchmarks that prepare inputs of various lengths (such as 2–5 elements) outside the loop, then call the method under test inside theb.N loop. This mirrors realistic workloads and isolates the operation cost.Why do different benchmarks show different values for b.N?
The harness adjustsb.N independently for each benchmark so each one runs long enough for reliable timing. As a result, b.N varies, but total time per benchmark is kept roughly comparable.
Learn Go with Pocket-Sized Projects ebook for free