Introduction to BenchmarkDotNet

03 januari 2022 om 10:00 by ParTech Media - Post a comment

Let’s begin with a simple question - How do you determine the effectiveness of a task in your business? 9 out of 10 would say - based on the time taken for completing the job.

Thanks to advancements in technology, the time taken for completing a particular job got reduced from days to hours or in some cases to milliseconds and nanoseconds. When the task was being done manually, there was always a scope for improvement either with the time taken or the precision of the result.

Computers generally do not make any calculation error unless there is a flaw in the code that is being used to achieve the results. Also, they are way faster in achieving the same results than when done manually.

Now, does it mean there is no scope of improvement for the computer whenever a task is performed? Absolutely no.

Whenever a task is performed manually, it takes human energy (physical and mental) to achieve the results. The more energy it takes, the more tiring it gets.

Similarly, in the case of computers, the amount of memory used for completing the task has to be minimum. This is totally dependent on the code. If too much memory is consumed, then the code has to be optimized.

When the memory is not handled properly, the application/system will crash.

But remember - the code as such will have lots of business logic for performing these tasks, so it is important that you first jot down the areas where you need to optimize the code. And even if you modify an area of code through the naked eye, how will you see the difference in the performance of the code?

To answer all these questions, we are going to learn about BenchmarkDotNet and how it can be used to optimize the code.

Table of contents

  1. Introduction to BenchmarkDotNet
  2. Implementation and Analysis using BenchmarkDotNet
  3. Conclusion

Introduction to BenchmarkDotNet

Benchmark, in general, indicates the measurement(s) related to the execution of something. It allows us to compare the results of the performance of a code to optimize them. BenchmarkDotNet is an open-source, lightweight .Net library that can transform the code methods into benchmarks. Without any additional code being written, developers can examine the code and optimize its performance as required.

It is available as a NuGet package and can be utilized in both .Net framework-based applications as well as .Net Core applications. Let us now see how to implement BenchmarkDotNet

Implementation and Analysis using BenchmarkDotNet

As we saw in the previous section, BenchmarkDotNet can be applied to both .Net Framework and .Net Core applications. In this section, we are going to implement BenchmarkDotNet on top of .Net Core-based console applications and explore a few scenarios to further examine the code and understand the parameters that are coming up in the benchmark’s response.

Consider you have a scenario in your application where you need to handle a large amount of data and you are not sure on what data type needs to be used for it as there are a lot of options available in .Net. For instance, a List or HashSet can be used to handle the data. But, we primarily want to understand its performance while reading/writing to them. So, let’s do that with an example.

Let's create a console-based application with .Net Core as its platform and provide a valid name for it.

The solution looks like below.’

Install the NuGet package - ‘BenchmarkDotNet’

Open the Program.cs file and add the below lines of code. The code has a new class - ‘SampleForBenchMark’ and has 4 methods for writing to list, writing to HashSet, reading from the list, and reading from HashSet.

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Running;
using System;
using System.Collections.Generic;

namespace PARTECH_Benchmark
{
  class Program
  {
​    static void Main(string[] args)
​    {
​      var summary = BenchmarkRunner.Run<SampleForBenchMark>();
​      Console.ReadLine();
​    }
  }

  [MemoryDiagnoser]
  [RankColumn, MinColumn, MaxColumn, AllStatisticsColumn]
  public class SampleForBenchMark
  
  {
​    static long iterationCount = 10;
​    [Benchmark]
​    public List<long> MesaureForList()
​    {
​     List<long> storage = new List<long>();
​     for (var i = 0; i < iterationCount; i++)

​      {
​        storage.Add(i);
​      }
​      return storage;
​    }
​    [Benchmark]

​    public HashSet<long> MesaureForHashSet()
​    {
​      HashSet<long> hashSetStorage = new HashSet<long>();
​      for (var i = 0; i < iterationCount; i++)

​      {
​        hashSetStorage.Add(i);
​      }
​      return hashSetStorage;
​    }
​    [Benchmark]
​    public void MesaureForListRead()

​    {
​      var input = MesaureForList();
​      for (var i = 0; i < iterationCount; i++)
​      {
​        var data = input.Find(x => x == i);
​      }
​    }
​    [Benchmark]
​    public void MesaureForHashSetRead()
​    {
​      var input = MesaureForHashSet();
​      for (var i = 0; i < iterationCount; i++)
​      {
​        var data = input.Contains(i);
​      }
​    }
  }
}

Now it's time for execution; Run the solution in Release mode and see if the console window pops up. And do you notice benchmark does some test runs and examines the code based on it? In the end, a result (in the below format) gets displayed in the console window.

  • Mean/Error/StdDev/StdError/MIn/Max - Indicates the time taken to execute the code. Lesser the value, faster the execution.
  • Rank - Provides the fastest-performing method. Lower the better.
  • Allocated - Bytes of memory allocated against all the generations of garbage collectors.

From the results, we can conclude that to write data, List performs way faster than HashSet. However, if we need to read data from a collection, then HashSet performs better than List.

With this data, developers can take a call on whether to use List or HashSet. If it is a one-time write and multiple reads throughout the application, then it is better to go with HashSet. On the other hand, if it is multiple write and single read, it is advised to go with Lists. Similarly, these data can be exported to graphs and reports.

Final Words

And that’s what BenchmarkingDotNet is all about The same process can be applied to various scenarios and can be used to examine the performance issues and optimize them as needed.