Go > Testing and Benchmarking > Benchmarking > Running benchmarks

Basic Benchmarking in Go

This snippet demonstrates how to write and run benchmarks in Go to measure the performance of a function. Benchmarking is crucial for identifying performance bottlenecks and optimizing code.

Writing a Benchmark Function

Benchmark functions in Go reside in the same packages as your tests, identified by names starting with `Benchmark`. The `testing.B` type provides methods for timing and controlling the benchmark execution. The `b.N` variable represents the number of iterations the benchmark will run. The `fibonacci` function is a simple recursive function that will be benchmarked.

package main

import "testing"

func fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return fibonacci(n-1) + fibonacci(n-2)
}

func BenchmarkFibonacci10(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fibonacci(10)
	}
}

Running the Benchmark

To run the benchmark, use the `go test` command with the `-bench` flag. The `.` pattern means run all benchmarks in the current directory. The `-benchmem` flag includes memory allocation statistics in the benchmark results.

// Save the above code in a file named fib_test.go
// Navigate to the directory containing fib_test.go in your terminal.
go test -bench=. -benchmem

Interpreting the Benchmark Results

The output shows the benchmark name (`BenchmarkFibonacci10`), the number of iterations (`1708552`), the average time per operation (`686.3 ns/op`), bytes allocated per operation (`0 B/op`), and the number of memory allocations per operation (`0 allocs/op`). The `goos` and `goarch` indicate the operating system and architecture where the benchmark was executed.

goos: darwin
 goarch: amd64
 pkg: your_package_name
 cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
 BenchmarkFibonacci10-12         1708552               686.3 ns/op          0 B/op          0 allocs/op
 PASS
 ok      your_package_name 1.396s

Concepts Behind the Snippet

Go's benchmarking framework is built into the `testing` package, making it easy to measure the performance of your code. The framework provides tools to control the number of iterations and report detailed statistics about execution time and memory usage. Understanding these statistics helps identify areas for optimization.

Real-Life Use Case

Consider a web server that processes a large number of requests. Benchmarking the request handling functions can help identify bottlenecks and optimize the server's performance. For example, you might benchmark different algorithms for processing incoming data or different data structures for storing session information. Benchmarking data serialization/deserialization or database access operations is also very common.

Best Practices

  • Isolate the Code Under Test: Ensure the benchmark focuses solely on the code you want to measure. Minimize external factors that could influence the results.
  • Use Representative Inputs: Choose input data that reflects real-world scenarios. A benchmark with unrealistic data may not accurately reflect performance in production.
  • Run Multiple Iterations: Go automatically adjusts the number of iterations to achieve stable results. However, you might need to adjust `b.N` manually if the benchmark is very short or long.
  • Compare Performance Over Time: Regularly run benchmarks to track performance changes as your code evolves. This helps identify performance regressions.

Interview Tip

Be prepared to discuss the purpose of benchmarking, how to write a basic benchmark function, and how to interpret the results. Understanding common performance metrics like time per operation, memory allocation, and the number of allocations is crucial. Be able to explain the difference between profiling and benchmarking.

When to Use Benchmarks

Use benchmarks when you need to optimize the performance of critical sections of your code. This is especially useful when comparing different algorithms or implementations. Benchmarks are also valuable for detecting performance regressions during development and for ensuring that changes don't negatively impact performance.

Memory Footprint

The `-benchmem` flag is useful for understanding the memory footprint of your code. Reducing memory allocations can often improve performance, especially in garbage-collected languages like Go. Consider using techniques like object pooling or pre-allocating memory to reduce allocations.

Alternatives

  • Profiling: Profiling is a broader technique for identifying performance bottlenecks in your entire application. Tools like `go tool pprof` can help you visualize where your program spends its time.
  • Performance Monitoring: Use tools to monitor the performance of your application in production. This can help you identify real-world performance issues that might not be apparent during testing.
  • Microbenchmarks vs. Macrobenchmarks: Microbenchmarks focus on small, isolated pieces of code. Macrobenchmarks measure the performance of larger, more complex systems. Choose the right type of benchmark for your needs.

Pros

  • Built-in support within the `testing` package simplifies writing and running benchmarks.
  • Provides detailed statistics about execution time and memory usage.
  • Helps identify performance bottlenecks and optimize code.

Cons

  • Microbenchmarks may not always accurately reflect real-world performance.
  • Can be time-consuming to write and maintain benchmarks.
  • Results can be influenced by external factors.

FAQ

  • How do I exclude certain benchmarks from running?

    You can use the `-bench` flag with a regular expression to specify which benchmarks to run. For example, `go test -bench=Fibonacci` will only run benchmarks that contain the word 'Fibonacci'.
  • Can I run benchmarks in parallel?

    Yes, you can use the `b.RunParallel` method to run benchmarks in parallel. This is useful for measuring the performance of concurrent code.
  • How do I reset the timer in a benchmark?

    Use `b.ResetTimer()` to reset the timer before starting the code you want to benchmark. This is useful for excluding setup code from the timing measurements.