An Introduction to Benchmarking Your Go Programs
In this article, we are going to be having a look at benchmarking. More specifically, we are going to be looking at how you can benchmark your Go-based programs.
In times where performance is important, being able to benchmark how your program performs and analyze where potential bottlenecks are, is really valuable. By understanding where these bottlenecks lie, we can more effectively determine where to focus our efforts in order to improve the performance of our systems.
Note - It’s important to note that performance tweaking should typically be done after the system is up and running.
“Premature optimization is the root of all evil” - Donald Knuth
In this tutorial, we are going to look at how we can perform standard benchmarking tests for very simple functions and then move on to more advanced examples before finally looking at how we can generate cool looking flame graphs.
A Simple Benchmark Test
Within Go, benchmarking tests can be written in conjunction with your standard unit tests. These benchmark functions should be prefixed by “Benchmark” followed by the function name, in the same manner, that you would prefix Test for your test functions.
Let’s take our code from our main.go
and add the following code to that file:
|
|
As you can see, it’s nothing crazy, we have a Calculate
function that takes in an int
value, adds 2 to that value and returns it. This is the perfect function to use for creating our first benchmark.
So, in order to write a benchmark for our Calculate
function then we can utilize part of the testing
package and write a function within our main_test.go
.
|
|
In order for us to run our new benchmark, we could simply run go test -bench=.
and it would run all benchmarks within our package for us. This should return something like so:
|
|
As you can see, it ran our Calculate()
function 2,000,000,000
times at a speed of 0.30 ns
per operation. The entire benchmark took just 0.653s
in order to run through.
Obviously, as more benchmarks are added to our suite, or the complexity of our functions increases, you should see these benchmarks taking longer and longer.
The -run Flag
In the above example, we ran our benchmarks in conjunction with our tests. This might not be ideal if you have a massive test suite and just want to validate performance improvements. If you want to specify that you only want to run your benchmark tests, then you can use the -run
flag.
This -run
flag takes in a regex pattern that can filter out the benchmarks we want to run. Let’s imagine that our main_test.go
file had 2 other test functions in it.
|
|
If we wanted to just run our Calculate tests, we could specify a regex that matches on Calculate
:
|
|
And this will trigger both our TestCalculate
and our BenchmarkCalculate
functions:
|
|
If we wanted to only run our BenchmarkCalculate
function then we could change our regex pattern to be:
|
|
And you’ll see in the above output that only our BenchmarkCalculate
function was triggered. As long as we keep a consistent naming convention for our benchmark functions, it should be fairly easy to specify a command that only tests them.
Increasing the Complexity.
Typically, you’ll want to benchmark your programs with a variety of distinct inputs. You want to measure the performance characteristics of your program under a number of distinct, real-life scenarios.
We’ll use our Calculate
function from the previous example and this time we’ll add in a suite of different benchmarks that test various different inputs for our function:
|
|
So, here we’ve created 3 distinct Benchmark functions that call benchmarkCalculate()
with various different types of input. This lets us see if there are any performance differences between different inputs and gives us a more accurate view as to how our program will perform in real life.
|
|
When writing your benchmark suites, it’s worthwhile fleshing out multiple benchmarks like this just to give you a far more accurate representation.
Conclusion
Hopefully this article gave you some indication as to how you can go about implementing your own suite of benchmarks. If you require further assistance then please let me know in the comments section below!
If you want to keep track of when new Go articles are posted to the site, then please feel free to follow me on twitter for all the latest news: @Elliot_F.