O BenchmarkDotNet ajuda você a transformar métodos em benchmarks, acompanhar seu desempenho e compartilhar experimentos de medição reprodutíveis. Não é mais difícil do que escrever testes de unidade! Sob o capô, ele realiza muita mágica que garante resultados confiáveis e precisos, graças ao mecanismo estatístico do Perfolizer. O BenchmarkDotNet protege você de erros populares de benchmarking e avisa se algo está errado com seu design de referência ou medições obtidas. Os resultados são apresentados em um formulário fácil de usar, que destaca todos os fatos importantes sobre o seu experimento. O BenchmarkDotNet já é adotado por mais de 22000 projetos do GitHub, incluindo .NET Runtime, .NET Compiler, .NET Performance e muitos outros.
É fácil começar a escrever benchmarks, confira o exemplo a seguir (a versão copy-usable está aqui):
[ SimpleJob ( RuntimeMoniker . Net472 , baseline : true ) ]
[ SimpleJob ( RuntimeMoniker . NetCoreApp30 ) ]
[ SimpleJob ( RuntimeMoniker . NativeAot70 ) ]
[ SimpleJob ( RuntimeMoniker . Mono ) ]
[ RPlotExporter ]
public class Md5VsSha256
{
private SHA256 sha256 = SHA256 . Create ( ) ;
private MD5 md5 = MD5 . Create ( ) ;
private byte [ ] data ;
[ Params ( 1000 , 10000 ) ]
public int N ;
[ GlobalSetup ]
public void Setup ( )
{
data = new byte [ N ] ;
new Random ( 42 ) . NextBytes ( data ) ;
}
[ Benchmark ]
public byte [ ] Sha256 ( ) => sha256 . ComputeHash ( data ) ;
[ Benchmark ]
public byte [ ] Md5 ( ) => md5 . ComputeHash ( data ) ;
}O BenchmarkDotNet executa automaticamente os benchmarks em todos os tempos de execução, agrega as medições e imprime uma tabela de resumo com as informações mais importantes:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.17763.805 (1809/October2018Update/Redstone5)
Intel Core i7-7700K CPU 4.20GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
[ Host ] : .NET Framework 4.7.2 (4.7.3468.0), X64 RyuJIT
Net472 : .NET Framework 4.7.2 (4.7.3468.0), X64 RyuJIT
NetCoreApp30 : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
NativeAot70 : .NET 7.0.0-preview.4.22172.7, X64 NativeAOT
Mono : Mono 6.4.0 (Visual Studio), X64
| Method | Runtime | N | Mean | Error | StdDev | Ratio |
| ------- | -------------- | ------ | -----------: | ----------: | ----------: | ------: |
| Sha256 | .NET 4.7.2 | 1000 | 7.735 us | 0.1913 us | 0.4034 us | 1.00 |
| Sha256 | .NET Core 3.0 | 1000 | 3.989 us | 0.0796 us | 0.0745 us | 0.50 |
| Sha256 | NativeAOT 7.0 | 1000 | 4.091 us | 0.0811 us | 0.1562 us | 0.53 |
| Sha256 | Mono | 1000 | 13.117 us | 0.2485 us | 0.5019 us | 1.70 |
| | | | | | | |
| Md5 | .NET 4.7.2 | 1000 | 2.872 us | 0.0552 us | 0.0737 us | 1.00 |
| Md5 | .NET Core 3.0 | 1000 | 1.848 us | 0.0348 us | 0.0326 us | 0.64 |
| Md5 | NativeAOT 7.0 | 1000 | 1.817 us | 0.0359 us | 0.0427 us | 0.63 |
| Md5 | Mono | 1000 | 3.574 us | 0.0678 us | 0.0753 us | 1.24 |
| | | | | | | |
| Sha256 | .NET 4.7.2 | 10000 | 74.509 us | 1.5787 us | 4.6052 us | 1.00 |
| Sha256 | .NET Core 3.0 | 10000 | 36.049 us | 0.7151 us | 1.0025 us | 0.49 |
| Sha256 | NativeAOT 7.0 | 10000 | 36.253 us | 0.7076 us | 0.7571 us | 0.49 |
| Sha256 | Mono | 10000 | 116.350 us | 2.2555 us | 3.0110 us | 1.58 |
| | | | | | | |
| Md5 | .NET 4.7.2 | 10000 | 17.308 us | 0.3361 us | 0.4250 us | 1.00 |
| Md5 | .NET Core 3.0 | 10000 | 15.726 us | 0.2064 us | 0.1930 us | 0.90 |
| Md5 | NativeAOT 7.0 | 10000 | 15.627 us | 0.2631 us | 0.2461 us | 0.89 |
| Md5 | Mono | 10000 | 30.205 us | 0.5868 us | 0.6522 us | 1.74 |
Os dados medidos podem ser exportados para diferentes formatos (MD, HTML, CSV, XML, JSON, etc.), incluindo parcelas:
Times de execução suportados: .NET 5+, .NET Framework 4.6.1+, .Net Core 3.1+, Mono, Nativeaot
Idiomas suportados: C#, F#, Visual Basic
SO suportado: Windows, Linux, MacOS
Arquiteturas suportadas: x86, x64, braço, braç64, wasm e loongarch64
O BenchmarkDotNet possui toneladas de recursos essenciais em investigações abrangentes de desempenho. Quatro aspectos definem o design desses recursos: simplicidade , automação , confiabilidade e simpatia .
Você não deve ser um engenheiro de desempenho experiente se quiser escrever benchmarks. Você pode projetar experimentos de desempenho muito complicados no estilo declarativo usando APIs simples.
Por exemplo, se você deseja parametrizar sua referência, marque um campo ou uma propriedade com [Params(1, 2, 3)] : BenchmarkDotNet enumerará todos os valores especificados e executará os benchmarks para cada caso. Se você deseja comparar os benchmarks entre si, marque um dos benchmarks como a linha de base via [Benchmark(Baseline = true)] : BenchmarkDotNet o comparará com todos os outros benchmarks. Se você deseja comparar o desempenho em diferentes ambientes, use trabalhos. Por exemplo, você pode executar todos os benchmarks no .NET Core 3.1 e Mono via [SimpleJob(RuntimeMoniker.NetCoreApp31)] e [SimpleJob(RuntimeMoniker.Mono)] .
Se você não gosta de atributos, pode chamar a maior parte das APIs através do estilo fluente e escrever código como este:
ManualConfig . CreateEmpty ( ) // A configuration for our benchmarks
. AddJob ( Job . Default // Adding first job
. WithRuntime ( ClrRuntime . Net472 ) // .NET Framework 4.7.2
. WithPlatform ( Platform . X64 ) // Run as x64 application
. WithJit ( Jit . LegacyJit ) // Use LegacyJIT instead of the default RyuJIT
. WithGcServer ( true ) // Use Server GC
) . AddJob ( Job . Default // Adding second job
. AsBaseline ( ) // It will be marked as baseline
. WithEnvironmentVariable ( "Key" , "Value" ) // Setting an environment variable
. WithWarmupCount ( 0 ) // Disable warm-up stage
) ;Se você preferir a experiência da linha de comando, pode configurar seus benchmarks por meio dos argumentos do console em qualquer aplicativo de console (outros tipos de aplicativos não são suportados).
Os benchmarks confiáveis sempre incluem um monte de código de caldeira.
Vamos pensar sobre o que você deve fazer em um caso típico. Primeiro, você deve realizar um experimento piloto e determinar o melhor número de invocações de métodos. Em seguida, você deve executar várias iterações de aquecimento e garantir que sua referência obtenha um estado estacionário. Depois disso, você deve executar as principais iterações e calcular algumas estatísticas básicas. Se você calcular alguns valores em sua referência, deverá usá -lo de alguma forma para evitar a eliminação do código morto. Se você usar loops, deve se preocupar com o efeito do loop que se desenrola nos seus resultados (que podem depender da arquitetura do processador). Depois de obter resultados, você deve verificar algumas propriedades especiais da distribuição de desempenho obtida, como multimodalidade ou outliers extremamente altos. Você também deve avaliar a sobrecarga da sua infraestrutura e deduzir de seus resultados. Se você deseja testar vários ambientes, execute as medições em cada uma delas e agregue manualmente os resultados.
Se você escrever este código do zero, é fácil cometer um erro e estragar suas medidas. Observe que é uma versão reduzida da lista de verificação completa que você deve seguir durante o benchmarking: existem muitas armadilhas ocultas adicionais que devem ser tratadas adequadamente. Felizmente, você não deve se preocupar com isso, porque a BenchmarkDotnet executará essas coisas chatas e demoradas para você.
Além disso, a biblioteca pode ajudá -lo com algumas tarefas avançadas que você pode executar durante a investigação. Por exemplo, o BenchmarkDotNet pode medir o tráfego de memória gerenciado e nativo e imprimir listagens de desmontagem para seus benchmarks.
Muitos benchmarks escritos à mão produzem números errados que levam a decisões de negócios incorretas. O BenchmarkDotNet protege você da maioria das armadilhas de benchmarking e permite alcançar alta precisão de medição.
Você não deve se preocupar com o número perfeito de invocação de métodos, o número de iterações de aquecimento e real: BenchmarkDotNet tenta escolher os melhores parâmetros de benchmarking e obter uma boa troca entre a previsão da medição e a duração total de todas as execuções de referência. Portanto, você não deve usar nenhum número mágico (como "devemos executar 100 iterações aqui"), a biblioteca fará isso com base nos valores das métricas estatísticas.
O BenchmarkDotNet também impede o benchmarking de conjuntos não otimizados que foram construídos usando o modo de depuração porque os resultados correspondentes não serão confiáveis. A biblioteca imprimirá um aviso se você tiver um depurador anexado, se usar um hipervisor (HyperV, VMware, VirtualBox) ou se tiver outros problemas com o ambiente atual.
Durante mais de 6 anos de desenvolvimento, enfrentamos dezenas de problemas diferentes que podem estragar suas medidas. Dentro do BenchmarkDotNet, há muitas heurísticas, verificações, hacks e truques que ajudam a aumentar a confiabilidade dos resultados.
A análise dos dados de desempenho é uma atividade demorada que requer atenção, conhecimento e experiência. O BenchmarkDotNet executa a parte principal desta análise para você e apresenta resulta em um formulário fácil de usar.
Após os experimentos, você obtém uma tabela de resumo que contém muitos dados úteis sobre os benchmarks executados. Por padrão, inclui apenas as colunas mais importantes, mas elas podem ser facilmente personalizadas. O conjunto de colunas é adaptável e depende da definição de referência e dos valores medidos. Por exemplo, se você marcar um dos benchmarks como uma linha de base, obterá colunas adicionais que o ajudarão a comparar todos os benchmarks com a linha de base. Por padrão, ele sempre mostra a coluna média, mas se detectarmos uma vasta diferença entre a média e os valores medianos, ambas as colunas serão apresentadas.
O BenchmarkDotNet tenta encontrar algumas propriedades incomuns de suas distribuições de desempenho e imprime boas mensagens sobre isso. Por exemplo, ele o alertará em caso de distribuição multimodal ou outliers altos. Nesse caso, você pode rolar os resultados para cima e verificar os histogramas de estilo ASCII para cada distribuição ou gerar lindas parcelas de PNG usando [RPlotExporter] .
BenchmarkDotNet não sobrecarrega você com dados; Ele mostra apenas as informações essenciais, dependendo dos seus resultados: permite manter o resumo pequeno para casos primitivos e estendê -las apenas para casos complicados. Obviamente, você pode solicitar estatísticas e visualizações adicionais manualmente. Se você não personalizar a visualização resumida, a apresentação padrão será o mais fácil possível. :)
O BenchmarkDotNet não é uma bala de prata que magicamente torna todos os seus benchmarks corretos e analisa as medidas para você. Mesmo se você usar esta biblioteca, ainda deve saber como projetar experimentos de referência e como tirar conclusões corretas com base nos dados brutos. Se você quiser saber mais sobre a metodologia de benchmarking e boas práticas, é recomendável ler um livro de Andrey Akinshin (o líder do projeto BenchmarkDotNet): "Pro .Net Benchmarking". Use este guia detalhado para projetar corretamente os benchmarks, meça as principais métricas de desempenho dos aplicativos .NET e analise os resultados. Este livro apresenta dezenas de estudos de caso para ajudá -lo a entender tópicos complicados de benchmarking. Você evitará armadilhas comuns, controlará a precisão de suas medições e melhorará o desempenho do seu software.
O BenchmarkDotNet já é uma biblioteca estável que permite executar a investigação de desempenho em nível profissional. E continua a evoluir! Adicionamos novos recursos o tempo todo, mas temos muitas idéias interessantes novas. Qualquer ajuda será apreciada. Você pode desenvolver novos recursos, corrigir bugs, melhorar a documentação ou fazer outras coisas legais.
Se você deseja contribuir, consulte os problemas do guia contribuinte e do up-for-brabs. Se você tiver novas idéias ou deseja reclamar de bugs, sinta -se à vontade para criar um novo problema. Vamos construir a melhor ferramenta para benchmarking juntos!
Este projeto adotou o Código de Conduta definido pelo Pacto Colaborador para esclarecer o comportamento esperado em nossa comunidade. Para obter mais informações, consulte o Código de Conduta da Fundação .NET.
O BenchmarkDotNet é suportado pelo AWS Open Sound Software Fund.