Nerd For Tech
Published in

Nerd For Tech

Benchmarking Your Solution in Go

Let’s benchmark your solution without any guessing! Then see is there any real improvement?

Photo by Ryan Quintal on Unsplash

After our system is up and running… After all refactoring sessions to make sure our code is clean, readable, and maintainable. Then it’s time for us to improve the system and making it better.

Quite often, there were several ways to attain better performance and most of them were achieved through experimentation. There would be questions like if I use this algorithm, will I get better performance? Or if I use this library instead of another library, will there be any significant difference? These questions could be answered without guessing or manual testing by doing benchmarking.

With benchmarking, we’ll have a piece of evidence for our solution. If it’s not doing any better, then we’ll move to another solution. Then all these solutions can be compared to one another, it will be easier for us to choose the best one.

Start with the basic

Let’s start with a simple example. Write this code in main.gofile.

We defined a simple function that mocks a certain operation that takes time to complete, in this case, it’s a random duration between 0 and 100 milliseconds. Simple and easy!

Now, let’s move into the benchmarking code. You can write this in main_test.go file. Remember that benchmarking is like any other test code.

You can run the test by typing go test -bench=. . But by doing this you’re not only run the benchmarking code, you’ll also run the test code (if you have one).

You can filter out the test to make sure that it’ll run the benchmarking code only by running go test -bench=Bench . Because all benchmark functions need to be started with Bench. Just like you define test functions with a wordTest at the start of the function name. If you want to be more specific then you can provide the flag -bench with the name of your benchmark function, e.g go test -bench=BenchmarkCalculate .

By default, the benchmark function is run for a minimum of 1 second. If the second has not elapsed when the Benchmark function returns, the value of b.N is increased in the sequence 1, 2, 5, 10, 20, 50, … and the function run again.

You could specify how long the benchmarking duration with command go test -bench=. -benchtime=20s . This command makes the benchmarking session takes 20 seconds to complete.

Benchmark RestAPI app

We’ll keep using our old Calculate function and use it in a RestAPI application. Plus, there will be an additional function that mocks a heavy operation named CalculateSlow. Now, let’s change our main.go file.

This application is pretty simple. It’s just containing one endpoint that uses Calculate and CalculateSlow. We have to specify x and y as a query string, then we’ll get the result.

How about the benchmarking code?

Certainly, a longer code compared to the one we had. I’ll explain this bit by bit.

  • You can run the code like before. But now we have 3 benchmark functions. By running command go test -bench=Bench -benchtime=5s . You’ll get something similar to this:
  • With a flag -benchtime=5s , each benchmark function will run at a minimum of 5 seconds.
  • Note that we’ve defined a package level variable result for storing the result we get from the API. All this is to avoid compiler optimisations and eliminating the function under test that will artificially lowering the run time of the benchmark.
  • If you switch the order of the benchmark functions, for example, BenchmarkCalculateRestAPI1 is defined first, you’ll get the same result. You see a quite difference between the first benchmark function and the second one is due to a random integer.
  • By seeing this result, inputs of one, one hundred and one million don’t make any significant difference. You’ll see this better by removing the random integer in Calculate function.

Is that it? Can we make our code better? Let’s look for a solution, like using a goroutine probably?

Making it better

Can we make our code better using the awesome feature Go has provided us, which is goroutine . Let’s find out.

By running command go test -bench=Bench -benchtime=5s , you’ll get this similar result:

See, because Calculate and CalculateSlow are running concurrently, we get a better result. Notice that for every benchmark function, we get approximately 2 seconds, which is the duration of sleep we defined in CalculateSlow . This is definitely a good solution to be implemented.

Conclusion

We started from a simple example to a real-world case, then we improved the previous code with a better solution.

The thing that we have to remember is performance tweaking must be done after the system is up and running. Not before that, or else we’ll be trapped in premature optimization.

Some solutions may require us to pull some tricks out of our sleeve that probably will make our code less obvious and readable. This would be a drawback we’d get by implementing the solution. But again, engineering is about knowing the solution we have has more advantages compared to disadvantages.

Thank you for reading and happy coding!

Other articles similar to this article:

--

--

--

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.

Recommended from Medium

Meta Machine Learning aggregator packages in R: Round II

Prismic Headless CMS vs Forestry Git Backed CMS

Prismic Headless CMS vs Forestry Git Backed CMS

CS371g Summer 2020 Week #7: Ramon Fabrega

Stockpile volume with Open3D

What is your deployment strategy

Our Enterprise Docker Solution for Migration to the Cloud

Fix PyPi Package Installation Issues on Cloud Composer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Agus Richard

Agus Richard

I am a Software Engineer and Data Science Enthusiast. Love to learn and write. LinkedIn: https://www.linkedin.com/in/agus-richard/

More from Medium

API development with type-safety across the entire stack

Testing a web server : Part 1

In conversation with Google’s gRPC | Part1

Running Redis at Scale — Redis Roadmap