その名の通り、任意のプログラムのベンチマークを取るためのライブラリ。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