C# – BenchmarkDotNet

By | 07/12/2022

In this post, we will see how to use the library BenchmarkDotNet for testing the performance of our methods.
But first of all, what is BenchmarkDotNet?
“BenchmarkDotNet is a lightweight, open-source, powerful .NET library that can transform our methods into benchmarks, track the performance, and then provide insights into the performance data captured”.
I want to specify that the purpose of this post it isn’t to cover all aspects of this library but, it provides just a starting point.

We start creating a console application called TestBenchmark and then, using the command:

Install-Package BenchmarkDotNet

we will install the library.

Then, we will add a class called Core where we will write two methods for creating a string.
The first one, called CreateWithString, uses a string that every time it will be modify instead the second one, called CreateWithStringBuilder, uses a stringbuilder:
[CORE.CS]

using System.Text;

namespace TestBenchmark;

public class Core
{
    public void CreateWithString()
    {
        string result = string.Empty;

        for (int i = 1; i < 100; i++)
        {
            result = result + $"Value{i}";
        }
    }

    public void CreateWithStringBuilder()
    {
        StringBuilder result = new StringBuilder();

        for (int i = 1; i < 100; i++)
        {
            result.Append($"Value{i}");
        }
    }
}



Now, we will add another class called BenchmarkCore where we will run the benchmarks for the two methods above:
[BENCHMARKCORE.CS]

using BenchmarkDotNet.Attributes;

namespace TestBenchmark;

[MemoryDiagnoser] // with this attribute we will measure the memory usage
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)] // with this parameter we define the order
[RankColumn] // with this attribute the system will show the Ranck column
public class BenchmarkCore
{
    private Core? objCore;

    [GlobalSetup] // with this attribute the system will use the method to initialize the variables
    public void GlobalSetup()
    {
        objCore = new Core();
    }

    [Benchmark] // with this attribute the system will use this method for the benchmark
    public void TestMethodCreateWithString()
    {
        objCore.CreateWithString();
    }

    [Benchmark] // with this attribute the system will use this method for the benchmark
    public void TestMethodCreateWithStringBuilder()
    {
        objCore.CreateWithStringBuilder();
    }
}



Then, we have to modify the Program file:
[PROGRAM.CS]

using BenchmarkDotNet.Running;
using TestBenchmark;

Console.WriteLine("Start Benchmark");

BenchmarkRunner.Run<BenchmarkCore>();



Finally, in order to run the benchmarks, we have to to run the application in release mode:

and then, after a while, this will be the result:

Method: it is the method’s name
Mean: it is the average of all measurements for the corresponding method
Rank: it is the relative position of all benchmarks
Allocated: it is the allocated memory per single operation



ARGUMENTS
If we need to test our methods using different values, we can use the attribute ARGUMENTS that in easy way it allows us to pass different values in a method.
For example, if we want to test the two methods above with different values like 10,100,1000 and 10000, we have to modify the code in this way:

[CORE.CS]

using System.Text;

namespace TestBenchmark;

public class Core
{
    public void CreateWithString(int totalItems)
    {
        string result = string.Empty;

        for (int i = 1; i < totalItems; i++)
        {
            result = result + $"Value{i}";
        }
    }

    public void CreateWithStringBuilder(int totalItems)
    {
        StringBuilder result = new StringBuilder();

        for (int i = 1; i < totalItems; i++)
        {
            result.Append($"Value{i}");
        }
    }
}



[BENCHMARKCORE.CS]

using BenchmarkDotNet.Attributes;

namespace TestBenchmark;

[MemoryDiagnoser] // with this attribute we will measure the memory usage
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)] // with this parameter we define the order
[RankColumn] // with this attribute the system will show the Ranck column
public class BenchmarkCore
{
    private Core? objCore;

    [GlobalSetup] // with this attribute the system will use the method to initialize the variables
    public void GlobalSetup()
    {
        objCore = new Core();
    }

    [Benchmark] // with this attribute the system will use this method for the benchmark
    // list of differnte input values
    [Arguments(10)] 
    [Arguments(100)]
    [Arguments(1000)]
    [Arguments(10000)]
    public void TestMethodCreateWithString(int totalItems)
    {
        objCore.CreateWithString(totalItems);
    }

    [Benchmark] // with this attribute the system will use this method for the benchmark
    // list of differnte input values
    [Arguments(10)]
    [Arguments(100)]
    [Arguments(1000)]
    [Arguments(10000)]
    public void TestMethodCreateWithStringBuilder(int totalItems)
    {
        objCore.CreateWithStringBuilder(totalItems);
    }
}



We have done and now, if we run the application (remember to run it in Release mode), this will be the result:



Category: C# Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *