0

Ticks の任意のメソッドの時間を測定するのに役立つクラスを作成しました。

基本的に、テスト メソッドを 100 回実行し、GC を強制してから、別の 100 回のメソッド実行にかかった時間を記録します。x64 リリース ctrl+f5 VS2012/VS2010

結果は次のとおりです。

2,914    2,909    2,913    2,909    2,908
2,907    2,909    2,998    2,976    2,855
2,446    2,415    2,435    2,401    2,402
2,402    2,399    2,401    2,401    2,400
2,399    2,400    2,404    2,402    2,401
2,399    2,400    2,402    2,404    2,403
2,401    2,403    2,401    2,400    2,399
2,414    2,405    2,401    2,407    2,399
2,401    2,402    2,401    2,404    2,401
2,404    2,405    2,368    1,577    1,579
1,626    1,578    1,576    1,578    1,577
1,577    1,576    1,578    1,576    1,578
1,577    1,578    1,576    1,578    1,577
1,579    1,585    1,576    1,579    1,577
1,579    1,578    1,579    1,577    1,578
1,577    1,578    1,576    1,578    1,577
1,578    1,599    1,579    1,578    1,582
1,576    1,578    1,576    1,579    1,577
1,578    1,577    1,591    1,577    1,578
1,578    1,576    1,578    1,576    1,578

ご覧のとおり、3 つのフェーズがあります。1 つ目は ~2,900、2 つ目は ~2,400、次に ~1,550 です。

それを引き起こす理由は何でしょうか?

アップデート

Intel I5 を使用したため、CPU ターボ ブーストが結果を妨げているのではないかと強く疑っています。ただし、ターボブーストを無効にしても、まだ安定していません。一方、Core 2 Quad は安定したベンチマークを生成します

テスト パフォーマンス クラスのコードは次のとおりです。

    public static void RunTests(Func<long> myTest)
    {
        const int numTrials = 100;
        Stopwatch sw = new Stopwatch();
        double[] sample = new double[numTrials];

        Console.WriteLine("Checksum is {0:N0}", myTest());

        sw.Start();
        myTest();
        sw.Stop();

        Console.WriteLine("Estimated time per test is {0:N0} ticks\n", sw.ElapsedTicks);


        for (int i = 0; i < numTrials; i++)
        {
            myTest();
        }
        GC.Collect();
        string testName = myTest.Method.Name;
        Console.WriteLine("----> Starting benchmark {0}\n", myTest.Method.Name);
        for (int i = 0; i < numTrials; i++)
        {
            sw.Restart();
            myTest();
            sw.Stop();
            sample[i] = sw.ElapsedTicks;
        }
        double testResult = DataSetAnalysis.Report(sample);

        for (int j = 0; j < numTrials; j = j + 5)
            Console.WriteLine("{0,8:N0} {1,8:N0} {2,8:N0} {3,8:N0} {4,8:N0}", sample[j], sample[j + 1], sample[j + 2], sample[j + 3], sample[j + 4]);
        Console.WriteLine("\n----> End of benchmark");
    }
4

3 に答える 3

1

あなたの投稿を正しく読むと、メソッドは 100 回しか実行されません。これは非常に小さなサンプル プールです。すぐにストップウォッチを行うとき、操作の複雑さに応じて、何百万もの操作を実行する傾向がありました。

一般的なケースのラッパーの場合、別のスレッドにストップウォッチを開始させ、パフォーマンス ピースに eventwaithandle シグナルを送信して実行し、ストップウォッチ スレッドが 2 分に達するまで 200 ミリ秒ごとにチェックし、シグナルを送信してパフォーマンス ピースをチェックする必要がある場合があります。すべての反復を停止するように通知します。

この 2 分間に完了した反復の数を確認します。

これを試して、10 回実行して、% 分散がカウントでどのくらいかを確認します。合計数は何千も異なる可能性がありますが、合計パーセント差ははるかに小さいはずです。

頭のてっぺんから..

public class PerfTester
{
    private EventWaitHandle _running = new EventWaitHandle(false, EventResetMode.ManualReset, "awesome_Woo");
    private int _count;

    public Run(Action actionToRun)
    {
        ParameterizedThreadStart runner = new ParameterizedThreadStart((state) =>
        {
            Action action = state as Action;
            EventWaitHandle run = = new EventWaitHandle(false, EventResetMode.ManualReset, "awesome_Woo", false);
            while(true)
            {
                run.WaitOne();
                action();
                _count++;
            }
        });

        Thread runnerThread = new Thread(runner);
        runnerThread.Start(actionToRun);

        StopWatch timer = new StopWatch();
        timer.Start();
        _running.Set();
        while(timer.ElapsedSeconds < 120) Thread.Sleep(500);
        _running.Reset();

        Console.WriteLine(_count);
    }
}

または、待機ハンドルの代わりにブール値を使用するだけかもしれません。境界を越えた通信にそれらを使用する習慣がついたばかりです..

于 2012-08-30T22:22:19.930 に答える
1

それはスピードステップのようですか?速度は 1/2x から始まり、完全にウォームアップすると全速力で動作します。

TMonitorを同時に実行すると、ベンチマークが安定し、ウォームアップの必要さえなくなります

于 2012-09-02T16:07:04.927 に答える
0

各ティックは約1000クロックサイクルだと思うので、1000〜2000ティックはそれほど小さくありません。それでも行う方が良いですが:

myTest();
myTest();
myTest();
myTest();
myTest();

myTest();
myTest();
myTest();
myTest();
myTest();

これは、ループコストを回避するために、ループを使用せずに同じメソッドを10回呼び出すことです。次に、結果を10で割ります。

違いについては、myTestコードがメモリ割り当てを行うか、任意の種類のキャッシュを使用するか、弱参照を使用する可能性があります。最近、.NetリフレクションAPIを呼び出すと、ローエンドマシンで奇妙なパフォーマンス結果が得られる可能性があることがわかりました。

于 2012-08-31T00:49:30.777 に答える