閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

BenchmarkDotNet

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

f:id:wata_d:20191203103244p:plain