Mastering Go Benchmarking: A Practical Guide to Performance Testing
This article introduces Go's benchmarking framework, explains its purpose and best practices, provides step‑by‑step code examples for measuring string concatenation performance, shows how to run benchmarks from the command line, and teaches how to interpret the detailed test reports.
What is Benchmarking
Benchmarking runs predefined tasks to measure system or code performance, focusing on execution time, memory consumption, throughput and latency. It provides quantitative data for comparing implementations, detecting regressions and guiding optimisations.
Go Benchmarking
In Go, benchmark functions receive a *testing.B argument. The testing framework repeatedly executes the benchmark code, automatically choosing the number of iterations ( b.N) to obtain stable timing and allocation statistics.
Writing Conventions
Naming : Functions must start with Benchmark followed by a descriptive name, e.g. BenchmarkStringConcat.
Signature : The sole parameter is *testing.B.
Loop control : Use b.N as the loop bound; the framework sets its value.
Avoid side effects : Ensure the benchmark code is repeatable and does not depend on external state.
Resource cleanup : Release any resources (files, network connections, etc.) after the benchmark, preferably with defer.
Code Example
The example compares two string‑concatenation techniques: the + operator and strings.Builder.
package test
import (
"strings"
"testing"
)
// Benchmark using + operator
func BenchmarkStringConcat(b *testing.B) {
setConfig(b)
str1 := "Hello"
str2 := "FunTester"
for i := 0; i < b.N; i++ {
_ = str1 + str2
}
}
// Benchmark using strings.Builder
func BenchmarkStringBuilder(b *testing.B) {
setConfig(b)
str1 := "Hello"
str2 := "FunTester"
for i := 0; i < b.N; i++ {
var builder strings.Builder
builder.WriteString(str1)
builder.WriteString(str2)
_ = builder.String()
}
}
func setConfig(b *testing.B) {
b.SetParallelism(4) // number of goroutines
b.ReportAllocs() // enable allocation reporting
b.SetBytes(1024) // bytes processed per operation
}Running Benchmarks
Execute from the command line (or IDE) with:
go test -bench . -cpu 1,2,4,8,12Interpreting the Report
The output includes OS, architecture and package information followed by per‑benchmark rows:
BenchmarkStringConcat-2 : 100,000,000 iterations, 11.61 ns/op, 0 B/op, 0 allocs/op, ~88 GB/s throughput.
BenchmarkStringConcat-4 : similar performance, 11.71 ns/op.
BenchmarkStringConcat-8 : 11.62 ns/op.
BenchmarkStringBuilder-2 : 34,372,545 iterations, 33.96 ns/op, 24 B/op, 2 allocs/op, ~30 GB/s throughput.
The total suite duration was about 7.95 seconds.
Conclusions
Performance : The + operator is considerably faster for simple concatenation.
Memory : BenchmarkStringConcat performs no allocations, whereas BenchmarkStringBuilder incurs modest allocations.
Test cost : The benchmark run completes in under ten seconds, indicating reasonable overhead.
Common *testing.B APIs
b.N: Number of iterations set by the framework. b.ResetTimer(): Reset the timer after setup work. b.StopTimer() / b.StartTimer(): Pause and resume timing around non‑benchmark code. b.ReportAllocs(): Include allocation statistics in the report. b.Log(args ...interface{}): Log information during a benchmark. b.SetBytes(n int64): Declare the amount of data processed per operation for throughput reporting. b.Run(name string, f func(b *B)): Run sub‑benchmarks for more complex scenarios.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
