Benchmark e Job Baselines

Para dimensionar seus resultados, você pode marcar um método de benchmark ou um trabalho como base. Vamos aprender essa característica por exemplos.


Amostra: IntroBenchmarkBaseline

Você pode marcar um método como uma linha de base com a ajuda de.[Benchmark(Baseline = true)]

Código fonte

using System.Threading;
using BenchmarkDotNet.Attributes;

namespace BenchmarkDotNet.Samples
{
    public class IntroBenchmarkBaseline
    {
        [Benchmark]
        public void Time50() => Thread.Sleep(50);

        [Benchmark(Baseline = true)]
        public void Time100() => Thread.Sleep(100);

        [Benchmark]
        public void Time150() => Thread.Sleep(150);
    }
}

Saída

Como resultado, você terá um resumo adicional na tabela de resumo:Ratio

|  Method |      Mean |     Error |    StdDev | Ratio |
|-------- |----------:|----------:|----------:|------:|
|  Time50 |  50.46 ms | 0.0779 ms | 0.0729 ms |  0.50 |
| Time100 | 100.39 ms | 0.0762 ms | 0.0713 ms |  1.00 |
| Time150 | 150.48 ms | 0.0986 ms | 0.0922 ms |  1.50 |

Esta coluna contém o valor médio da distribuição da razão.

Por exemplo, no caso de, nós dividimos a primeira medição da primeira medição de (é a linha de base), a segunda medição da segunda medição de, e assim por diante. Em seguida, calculamos a média de todos esses valores e exibimos-no na coluna. Pois, temos 0,50.Time50Time50Time100Time50Time100RatioTime50

Thecolumn era anteriormente conhecido como. O título antigo era uma fonte de mal-entendido e confusão, porque muitos desenvolvedores interpretaram-no como a razão de meios (por exemplo,/para). A razão de distribuição significa e a média da distribuição da razão estão muito próximas umas das outras na maioria dos casos, mas eles não são iguais.RatioScaled50.46100.39Time50

Em @BenchmarkDotNet.Samples.IntroRatioStdDev, você pode encontrar um exemplo de como esse valor pode ser estragado por outliers.


Amostra: IntroRatiosd

A proporção de dois benchmarks não é um único número, é uma distribuição. Na maioria dos casos simples, a faixa da distribuição da razão é estreita, e o BenchmarkDotNet exibe uma única coluna com o valor médio. No entanto, também adiciona olumn (o desvio padrão da distribuição da razão) em situações complexas. No exemplo abaixo, o benchmark da linha de base é estragado por um outlier únicoRatioRatioSD

Código fonte

using System.Threading;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using Perfolizer.Mathematics.OutlierDetection;

namespace BenchmarkDotNet.Samples
{
    // Don't remove outliers
    [Outliers(OutlierMode.DontRemove)]
    // Skip jitting, pilot, warmup; measure 10 iterations
    [SimpleJob(RunStrategy.Monitoring, targetCount: 10, invocationCount: 1)]
    public class IntroRatioSD
    {
        private int counter;

        [GlobalSetup]
        public void Setup() => counter = 0;

        [Benchmark(Baseline = true)]
        public void Base()
        {
            Thread.Sleep(100);
            if (++counter % 7 == 0)
                Thread.Sleep(5000); // Emulate outlier
        }

        [Benchmark]
        public void Slow() => Thread.Sleep(200);

        [Benchmark]
        public void Fast() => Thread.Sleep(50);
    }
}

Saída

Aqui estão os detalhes estatísticos para o benchmark da linha de base:

Mean = 600.6054 ms, StdErr = 500.0012 ms (83.25%); N = 10, StdDev = 1,581.1428 ms
Min = 100.2728 ms, Q1 = 100.3127 ms, Median = 100.4478 ms, Q3 = 100.5011 ms, Max = 5,100.6163 ms
IQR = 0.1884 ms, LowerFence = 100.0301 ms, UpperFence = 100.7837 ms
ConfidenceInterval = [-1,789.8568 ms; 2,991.0677 ms] (CI 99.9%), Margin = 2,390.4622 ms (398.01% of Mean)
Skewness = 2.28, Kurtosis = 6.57, MValue = 2
-------------------- Histogram --------------------
[-541.891 ms ;  743.427 ms) | @@@@@@@@@
[ 743.427 ms ; 2027.754 ms) | 
[2027.754 ms ; 3312.082 ms) | 
[3312.082 ms ; 4458.453 ms) | 
[4458.453 ms ; 5742.780 ms) | @
---------------------------------------------------

Como você pode ver, um único outlier afetou significativamente as métricas. Por causa disso, o BenchmarkDotNet adiciona the e thecolumns na tabela de resumo:MedianRatioSD

 Method |      Mean |         Error |        StdDev |    Median | Ratio | RatioSD |
------- |----------:|--------------:|--------------:|----------:|------:|--------:|
   Base | 600.61 ms | 2,390.4622 ms | 1,581.1428 ms | 100.45 ms |  1.00 |    0.00 |
   Slow | 200.50 ms |     0.4473 ms |     0.2959 ms | 200.42 ms |  1.80 |    0.62 |
   Fast |  50.54 ms |     0.3435 ms |     0.2272 ms |  50.48 ms |  0.45 |    0.16 |

Vamos olhar para as marcas de banco de trabalho. Os valores são emilliseconds; o valor “Média Escalonada” é de 0,3. Os valores são emilliseconds; o valor “Mediana Escalonada” é 2. Ambos os valores são enganosos. O BenchmarkDotNet avalia a distribuição da razão e exibe a média (1,80) e o desvio padrão (0,62).BaseSlowMean600200Median100200


Amostra: IntroCategoryBaseline

A única maneira de ter várias linhas de base na mesma classe é separá-las por categorias e marcar a classe com.[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]

Código fonte

using System.Threading;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;

namespace BenchmarkDotNet.Samples
{
    [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
    [CategoriesColumn]
    public class IntroCategoryBaseline
    {
        [BenchmarkCategory("Fast"), Benchmark(Baseline = true)]
        public void Time50() => Thread.Sleep(50);

        [BenchmarkCategory("Fast"), Benchmark]
        public void Time100() => Thread.Sleep(100);

        [BenchmarkCategory("Slow"), Benchmark(Baseline = true)]
        public void Time550() => Thread.Sleep(550);

        [BenchmarkCategory("Slow"), Benchmark]
        public void Time600() => Thread.Sleep(600);
    }
}

Saída

|  Method | Categories |      Mean |     Error |    StdDev | Ratio |
|-------- |----------- |----------:|----------:|----------:|------:|
|  Time50 |       Fast |  50.46 ms | 0.0745 ms | 0.0697 ms |  1.00 |
| Time100 |       Fast | 100.47 ms | 0.0955 ms | 0.0893 ms |  1.99 |
|         |            |           |           |           |       |
| Time550 |       Slow | 550.48 ms | 0.0525 ms | 0.0492 ms |  1.00 |
| Time600 |       Slow | 600.45 ms | 0.0396 ms | 0.0331 ms |  1.09 |

Amostra: IntroJobBaseline

Se você quiser comparar várias configurações de tempo de execução, você pode marcar um de seus trabalhos com.baseline = true

Código fonte

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;

namespace BenchmarkDotNet.Samples
{
    [SimpleJob(runtimeMoniker: RuntimeMoniker.Net462, baseline: true)]
    [SimpleJob(runtimeMoniker: RuntimeMoniker.Mono)]
    [SimpleJob(runtimeMoniker: RuntimeMoniker.Net50)]
    public class IntroJobBaseline
    {
        [Benchmark]
        public int SplitJoin()
            => string.Join(",", new string[1000]).Split(',').Length;
    }
}

Saída

BenchmarkDotNet=v0.10.12, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Processor=Intel Core i7-6700HQ CPU 2.60GHz (Skylake), ProcessorCount=8
Frequency=2531249 Hz, Resolution=395.0619 ns, Timer=TSC
.NET Core SDK=2.0.3
  [Host]     : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
  Job-MXFYPZ : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2600.0
  Core       : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
  Mono       : Mono 5.4.0 (Visual Studio), 64bit 
    Method | Runtime |     Mean |     Error |    StdDev | Ratio | RatioSD |
---------- |-------- |---------:|----------:|----------:|------:|--------:|
 SplitJoin |     Clr | 19.42 us | 0.2447 us | 0.1910 us |  1.00 |    0.00 |
 SplitJoin |    Core | 13.00 us | 0.2183 us | 0.1935 us |  0.67 |    0.01 |
 SplitJoin |    Mono | 39.14 us | 0.7763 us | 1.3596 us |  2.02 |    0.07 |


Artigo Original