Dica Rápida: Testando desempenho com BenchmarkDotNet

William Santos - Apr 12 '21 - - Dev Community

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 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:



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();
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

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:



using BenchmarkDotNet.Running;

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


Enter fullscreen mode Exit fullscreen mode

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.

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 (em inglês).

Até a próxima!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .