Dica Rápida: Testando desempenho com BenchmarkDotNet
Tags: csharp, dotnet, benchmark, braziliandevs
Published: 2021-04-12 14:52:57

Olá!

Este é mais um post da seção Dica Rápida e, desta vez, falaremos sobre uma ferramenta muito útil para avaliar o desempenho de nosso código: o BenchmarkDotNet.

O BenchmarkDotNet é uma biblioteca disponível no [NuGet](https://www.nuget.org/packages/BenchmarkDotNet/) que, uma vez adicionada ao seu projeto, te permite executar testes de desempenho de forma bem semelhante à de testes de unidade.

Vamos fazer um pequeno teste. Para isso, crie um novo projeto do tipo `Console` chamado `Lab.Benchmark.Linq`, adicione a biblioteca BenchmarkDotNet e, em seguida, crie um arquivo chamado LinqBenchmark.cs, e adicione o seguinte conteúdo:

```c#
using BenchmarkDotNet.Attributes;
using System;
using System.Linq;

namespace Lab.Benchmark.Linq
{
    public class LinqBenchmark
    {
        private const int capacity = 1000;
        private const int slice = 500;
        private int[] numbers = new int[capacity];

        [GlobalSetup]
        public void Setup()
        {
            for (int i = 0; i < capacity; i++)
                numbers[i] = i;
        }

        [Benchmark]
        public int LinqWhereAndFirst() =>
            numbers.Where(x => x > slice).First();

        [Benchmark]
        public int LinqFirst() =>
            numbers.First(x => x > slice);

        [Benchmark(Baseline=true)]
        public int NoLinq()
        {
            for (int i = 0; i < numbers.Length; i++)
                if (numbers[i] > slice)
                    return numbers[i];

            throw new InvalidOperationException();
        }
    }
}
```

Vamos verificar o conteúdo deste arquivo. Repare que temos um atributo chamado `GlobalSetup` sobre o método `Setup`. Este atributo indica que antes da execução de qualquer benchmark este método será executado.

Em seguida, temos métodos marcados com o atributo `Benchmark`, que indica que se trata de um método de medição (da mesma forma que um método de teste no XUnit, por exemplo, teria um atributo `Fact` ou `Theory`). No último método temos, além do atributo `Benchmark`, a propriedade `Baseline` com value `true`. Isso significa que este será o baseline de nossa medição, ou seja, o ponto de referência para as demais execuções. Este atributo é opcional, e adiciona o número de vezes que o baseline poderia ser executado no tempo de execução dos demais métodos.

Com isto, temos o mínimo necessário para executar nosso benchmark.

Vamos agora ao arquivo Program.cs, e substituir o conteúdo original pelo seguinte:

```C#
using BenchmarkDotNet.Running;

namespace Lab.Benchmark.Linq
{
    static class Program
    {
        static void Main(string[] args)
        {
			BenchmarkRunner.Run<LinqBenchmark>();
        }
    }
}
```

Aqui temos apenas uma chamada para o método `Run` do executor de benchmarks, especificando o tipo `LinqBenchmark` que criamos acima.

Para executar o benchmark, basta configurar o build do projeto para `Release`, e executar este programa sem habilitar o debugger (Ctrl +F5).

Se tudo deu certo, o resultado será semalhante ao da imagem abaixo.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnwwbriz3tra2m1o62ea.png)

E assim temos um teste de desempenho de três implementações distintas de um mesmo algoritmo.

Para maiores informações sobre a biblioteca, recomendo sua documentação no [Github](https://github.com/dotnet/BenchmarkDotNet) (em inglês).

Até a próxima!