Performance de código em .NET: implementando testes com BenchmarkDotNet

Renato Groffe
4 min readSep 27, 2021

--

Ao implementarmos aplicações iremos invariavelmente nos deparar com várias possibilidades de implementações, funcionalidades, recursos e mesmo frameworks para atender a uma demanda específica. Tais fatos são inerentes à própria atividade de desenvolvimento de software, cabendo a profissionais desta área encontrar meios para comparar as alternativas mais viáveis. Pesarão neste momento aspectos como o esforço de codificação, questões financeiras, a maturidade dos envolvidos em um projeto e, até mesmo, ganhos de performance em frações de tempo.

No que se refere à performance, é importante encontrar um meio de realizar comparações (benchmarkings) entre as opções existentes. E, obviamente, sem que tudo isso resulte em grandes malabarismos em termos de codificação.

A boa notícia dentro da plataforma .NET é que já contamos com uma alternativa para a geração de benchmarkings sofisticados, porém com um esforço relativamente pequeno: trata-se do projeto BenchmarkDotNet.

O BenchmarkDotNet é uma iniciativa open source mantida pela .NET Foundation e utilizada até mesmo por equipes de produto dentro da própria Microsoft! Empregando análises estatísticas, este projeto é capaz de retornar métricas como o tempo médio de execução de um código, o desvio padrão e a margem de erro do cálculo efetuado.

E aproveito esse espaço para um convite…

Dia 27/09 (segunda) às 21:00 horário de Brasília — teremos mais um evento online e gratuito no canal Canal .NET.

Ao longo desta live abordarei dicas, truques e alternativas úteis para o desenvolvimento Back-End e de APIs REST com .NET 5, ASP.NET Core, Azure Functions. Ao longo da apresentação será coberto o uso de diferentes frameworks, serviços na nuvem, mensageria, bancos de dados e boas práticas de forma a facilitar e tornar mais dinâmica a implementação de soluções baseadas na plataforma .NET no seu dia a dia.

Teremos também algumas novidades do .NET 6 demonstradas na prática!

Para participar faça sua inscrição no link a seguir, a transmissão acontecerá via YouTube:

https://bit.ly/live-backend-dotnet-set-2021

O exemplo de uso do BenchmarkDotNet demonstrado neste artigo foi disponibilizado no GitHub:

https://github.com/renatogroffe/DotNet5-BenchmarkDotNet-Testes-JSON_Serialization-V2

Para demonstrar a utilização do BenchmarkDotNet efetuarei uma comparação entre o mecanismo de serialização da biblioteca Newtonsoft e recursos que integram o namespace System.Text.Json. Para isto foram adicionados ao projeto os packages BenchmarkDotNet e Newtonsoft.Json:

A classe Regiao servirá de base para os testes com mecanismos de serialização:

Na próxima listagem temos o código da classe NewtonsoftVsSystemTextJson, em que foram definidos os métodos para testes:

  • O método Setup foi marcado com o atributo GlobalSetup, indicando a utilização do mesmo para fins de inicialização (criação de um array de objetos do tipo Regiao);
  • Já os métodos SerializeWithNewtonsoft (utilizando a serialização da biblioteca Newtonsoft) e SerializeWithSystemTextJson (com a serialização via recursos do namespace System.Text.Json) estão marcados com o atributo Benchmark, especificando com isto os testes a serem executados para a geração das análises.

Por fim, chegamos à implementação da classe Program. O método Run invocado a partir do tipo BenchmarkSwitcher no método Main permitirá que os testes sejam executados, tornando possível inclusive a passagem de parâmetros através da linha de comando:

A execução dos testes será por meio do comando dotnet run, utilizando configurações de Release e com o parâmetro --filter indicando quais testes a considerar (* para todos):

dotnet run -c Release --filter *

Que ao ser acionado mostrará que todos os benchmarkings serão executados:

E assim teremos um resultado similar ao da imagem a seguir (com o cálculo do número de iterações/execuções gerado automaticamente pelo BenchmarkDotNet por default, embora seja possível especificar um número na linha de comando). Podemos observar aqui a presença de valores estatísticos como média (Mean), mediana (Median), desvio padrão (StdDev) e margem de erro (Error):

Em um novo teste podemos informar como fitro *WithSystemTextJson, de maneira que apenas o benchmarking que avalia o uso do namespasce System.Text.Json seja disparado (as strings para filtros se baseiam na hierarquia namespace + classe + método):

dotnet run -c Release --filter *WithSystemTextJson

E com isto apenas o método SerializeWithSystemTextJson foi considerado no resultado final:

Essas execuções também geram arquivos com os resultados, com os mesmos disponibilizados no diretório BenchmarkDotNet.Artifacts:

Na próxima imagem estão alguns desses arquivos (gerados em formatos texto, HTML, CSV e Markdown):

O arquivo HTML traria uma visão similar à encontrada na próxima imagem, por exemplo:

--

--

Renato Groffe

Microsoft Most Valuable Professional (MVP), Multi-Plataform Technical Audience Contributor (MTAC), Software Engineer, Technical Writer and Speaker