BenchmarkDotNet
その名の通り、任意のプログラムのベンチマークを取るためのライブラリ。C#で書いたメソッドのパフォーマンスを計るのに、いちいちStopwatch.StartNewして…とかしなくてよくなります。メソッドを複数回実行してその平均を結果として出力する、みたいなことも全自動でやってくれます。
ちょっと前のxUnitみたいな使い方で、ベンチマークを計るためのクラスを作って
BenchmarkDotNet.Running.BenchmarkRunner.Run<ArraySum>();
と書いて実行するとArraySumクラス内に書いたベンチマークが実行され、コンソールやファイルに結果が出力される。
"ベンチマークを計るためのクラス"には、やはりxUnitのように属性でメソッドにベンチマークを計るものである旨を指定しておく。
[BenchmarkDotNet.Attributes.MemoryDiagnoser]
public class ArraySum
{
[BenchmarkDotNet.Attributes.Params(10, 100, 1000, 10000, 100000, 1000000)]
public int Count;
public int Start => 1;
public int Stop => Count - 1;
private long[] _array;
[BenchmarkDotNet.Attributes.GlobalSetup]
public void Setup()
{
_array = Enumerable.Range(0, Count).Select(x => (long)x).ToArray();
}
[BenchmarkDotNet.Attributes.Benchmark]
public long Sum_Index()
{
long sum = 0;
for (var i = Start; i < Stop; i++)
{
sum += _array[i];
}
return sum;
}
[BenchmarkDotNet.Attributes.Benchmark]
public long Sum_Linq()
{
return _array.Skip(Start).Take(Stop - Start).Sum();
}
[BenchmarkDotNet.Attributes.Benchmark]
public long Sum_Range()
{
return _array[Start..Stop].Sum();
}
[BenchmarkDotNet.Attributes.Benchmark]
public long Sum_Span()
{
long sum = 0;
foreach (var n in _array.AsSpan(Start..Stop))
{
sum += n;
}
return sum;
}
}
実行すると実行ファイルのあるディレクトリの下に BenchmarkDotNet.Artifacts/results ディレクトリが作られ、デフォルト設定ではcsv/html/md/Rファイルが作成されます。
mdファイルにはMarkdown形式で結果が出力されるので、以下の通り、そのままコピペで表にできます。
Method |
Count |
Mean |
Error |
StdDev |
Gen 0 |
Gen 1 |
Gen 2 |
Allocated |
Sum_Index |
10 |
5.619 ns |
0.0054 ns |
0.0047 ns |
- |
- |
- |
- |
Sum_Linq |
10 |
200.515 ns |
0.8479 ns |
0.7931 ns |
0.0203 |
- |
- |
96 B |
Sum_Range |
10 |
83.320 ns |
1.4429 ns |
1.3497 ns |
0.0254 |
- |
- |
120 B |
Sum_Span |
10 |
14.047 ns |
0.0652 ns |
0.0610 ns |
- |
- |
- |
- |
Sum_Index |
100 |
81.580 ns |
0.1521 ns |
0.1348 ns |
- |
- |
- |
- |
Sum_Linq |
100 |
1,168.466 ns |
3.7833 ns |
3.3538 ns |
0.0191 |
- |
- |
96 B |
Sum_Range |
100 |
666.825 ns |
10.7970 ns |
10.0995 ns |
0.1783 |
- |
- |
840 B |
Sum_Span |
100 |
79.600 ns |
0.1045 ns |
0.0926 ns |
- |
- |
- |
- |
Sum_Index |
1000 |
763.410 ns |
0.6491 ns |
0.5420 ns |
- |
- |
- |
- |
Sum_Linq |
1000 |
10,923.124 ns |
24.0253 ns |
21.2978 ns |
0.0153 |
- |
- |
96 B |
Sum_Range |
1000 |
6,333.975 ns |
21.1066 ns |
19.7431 ns |
1.7014 |
- |
- |
8040 B |
Sum_Span |
1000 |
729.695 ns |
0.6874 ns |
0.6429 ns |
- |
- |
- |
- |
Sum_Index |
10000 |
7,618.156 ns |
6.3278 ns |
5.6094 ns |
- |
- |
- |
- |
Sum_Linq |
10000 |
107,975.718 ns |
47.8050 ns |
39.9194 ns |
- |
- |
- |
97 B |
Sum_Range |
10000 |
62,339.152 ns |
242.7192 ns |
215.1643 ns |
16.8457 |
- |
- |
80040 B |
Sum_Span |
10000 |
7,209.591 ns |
4.5585 ns |
4.2640 ns |
- |
- |
- |
- |
Sum_Index |
100000 |
76,212.827 ns |
41.3885 ns |
34.5613 ns |
- |
- |
- |
- |
Sum_Linq |
100000 |
1,078,386.523 ns |
550.1768 ns |
459.4226 ns |
- |
- |
- |
99 B |
Sum_Range |
100000 |
1,020,249.661 ns |
18,760.3401 ns |
17,548.4338 ns |
248.0469 |
248.0469 |
248.0469 |
800048 B |
Sum_Span |
100000 |
72,185.765 ns |
163.9998 ns |
153.4055 ns |
- |
- |
- |
1 B |
Sum_Index |
1000000 |
841,592.321 ns |
26,717.0160 ns |
29,695.8925 ns |
- |
- |
- |
- |
Sum_Linq |
1000000 |
10,821,178.646 ns |
30,006.0666 ns |
28,067.6933 ns |
- |
- |
- |
172 B |
Sum_Range |
1000000 |
8,130,877.404 ns |
52,434.7503 ns |
43,785.3913 ns |
328.1250 |
328.1250 |
328.1250 |
8000053 B |
Sum_Span |
1000000 |
655,597.043 ns |
12,825.4812 ns |
19,967.7291 ns |
- |
- |
- |
- |
Rのファイル(BuildPlots.R)はR言語で評価するとベンチマーク結果のチャートを描画できます。なぜRなのかはわからないけどw