1. ホーム
  2. c#

[解決済み] C#の小さなコードサンプルのベンチマーク、この実装は改善できるのか?

2022-10-29 12:56:27

質問

SOではしばしば、どの実装が最も速いかを見るために、コードの小さな塊をベンチマークしている自分に気づきます。

ベンチマークコードはジッターやガベージコレクタを考慮していないというコメントをよく見かけます。

私は以下のような簡単なベンチマーク関数を持っており、少しずつ進化させています。

  static void Profile(string description, int iterations, Action func) {
        // warm up 
        func();
        // clean up
        GC.Collect();

        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < iterations; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    }

使用方法

Profile("a descriptions", how_many_iterations_to_run, () =>
{
   // ... code being profiled
});

この実装には何か欠陥がありますか?実装Xは実装YよりもZ回の繰り返しで高速であることを示すのに十分でしょうか?これを改善する方法を思いつきますか?

EDIT 時間ベースのアプローチ(反復ではなく)が好ましいことは明らかですが、時間チェックがパフォーマンスに影響を与えないような実装をお持ちの方はいらっしゃいますか?

どのように解決するのですか?

コミュニティによって推奨されるように、この機能を修正するのは自由です。

static double Profile(string description, int iterations, Action func) {
    //Run at highest priority to minimize fluctuations caused by other processes/threads
    Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
    Thread.CurrentThread.Priority = ThreadPriority.Highest;

    // warm up 
    func();

    var watch = new Stopwatch(); 

    // clean up
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    watch.Start();
    for (int i = 0; i < iterations; i++) {
        func();
    }
    watch.Stop();
    Console.Write(description);
    Console.WriteLine(" Time Elapsed {0} ms", watch.Elapsed.TotalMilliseconds);
    return watch.Elapsed.TotalMilliseconds;
}

必ず 最適化を有効にして Release でコンパイルし、Visual Studio の外部でテストを実行します。 . この最後の部分は重要です。なぜなら、JITはReleaseモードであっても、デバッガが接続されていると最適化を抑制するからです。