正しくベンチマークを学習する(反復子を含む)

前回の投稿からサンプルをダウンロードしました。開始から開始までの時間は、最大1.5回、0.76秒から1.09秒まで変動しました。 そのようなベンチマークの結果をどのように評価できるかは不明です。 問題はおなじみで、昨日私は偶然に遭遇して解決しました。 要するに、CPUスロットリングも原因であり、コードの奇妙な親和性も同様です。 カットの戦い(成功)と議論の下で。

したがって、イテレーターに関する前の例、VS 2005、4回実行されます。 マシンが完全にアンロードされ、トレントなどがバックグラウンドで実行されていません。winampがオフになっている場合でも。 (ちなみに、CPUにバインドされたワークロードの場合、Winampおよびトレントでさえ、最大1〜2%の大きなジッターを作成しません。)結果は0.758から1.085になり、ほぼ1.5倍になります。 異なる走行で、また、異なる勝利で、これはレースには受け入れられません。 ;)

x = 3256681784 iterator++. Total time : 0.795557
x = 3256681784 ++iterator. Total time : 0.892076

x = 3256681784 iterator++. Total time : 1.08741
x = 3256681784 ++iterator. Total time : 1.0848

x = 3256681784 iterator++. Total time : 0.898355
x = 3256681784 ++iterator. Total time : 0.758123

x = 3256681784 iterator++. Total time : 0.906159
x = 3256681784 ++iterator. Total time : 0.861794


元気? コードを見ると、QPCがあり、その前にSetThreadAffinityMaskがあります。 反逆、本部は私たちのものではありません。 C2Dプロセッサ。異なるコアで異なる周波数を維持できます。 また、ダウンタイム時には、OSはこれを利用して頻度を減らします。 一方のコアでタイマー(QueryPerformanceFrequency)を調整し、もう一方のコアまたは同じコアでカウンターデータ(QueryPerformanceCounter)を読み取りますが、頻度を増やした後にゴミが発生します。

SetThreadAffinityMaskで1文字を正確に変更し、2番目のパラメーターを0ではなく1に設定します。

x = 3256681784 iterator++. Total time : 0.751778
x = 3256681784 ++iterator. Total time : 0.685859

x = 3256681784 iterator++. Total time : 0.737615
x = 3256681784 ++iterator. Total time : 0.686026

x = 3256681784 iterator++. Total time : 0.736503
x = 3256681784 ++iterator. Total time : 0.688713

x = 3256681784 iterator++. Total time : 0.772983
x = 3256681784 ++iterator. Total time : 0.68895


はるかに良い。 最初のテストは、0.736から0.772に震えています。 50%ではなく5%ずつ。 0.686から0.689までの2番目、それら。 0.4%。 違いはどこから来ますか?

仮説。 2番目のテストが開始されるまでに、キャッシュは熱くなります。 コードを注意深く読みました。 ただし、5000回の実行があり、コールドキャッシュは最初のもののみを変更します。 仮説は正しくありません。

仮説。 最初のテストが最初です。 おそらく、コア周波数の増加はそのプロセスで発生します。 さて、すべてのテストの前にプロセッサを温めましょう。 コンパイラーは非常に賢く、定数、特に使用されていない定数の計算と最適化に努めているため、volatileマジック修飾子を思い出します。 リビルド、おっと、助けにはならなかった。 親和性について覚えておいてください。 タイミングを合わせたピースだけでなく、プロセス全体を1つのコアに打ち破ります(そうしないと、間違ったコアを加熱する危険性があります)。 リビルド、おっと、勝利! このような4行のプログラムの最初に置いた合計。

  SetProcessAffinityMask(GetCurrentProcess(), 1); volatile int zomg = 1; for ( int i=1; i<1000000000; i++ ) zomg *= i; 


そして結果を楽しんでください。

x = 3256681784 iterator++. Total time : 0.687585
x = 3256681784 ++iterator. Total time : 0.685685

x = 3256681784 iterator++. Total time : 0.687524
x = 3256681784 ++iterator. Total time : 0.68579

x = 3256681784 iterator++. Total time : 0.686004
x = 3256681784 ++iterator. Total time : 0.688326

x = 3256681784 iterator++. Total time : 0.688472
x = 3256681784 ++iterator. Total time : 0.685775


ビンゴ ジッタは1%未満であり、これは非常に正常です。 そして今、最後に、違いはありません。 実際には、理論上そうあるべきです。 (このリリースでは、両方のイテレーターはポインターウォークで展開する必要があります。もちろん、SECURE_SCLをオンにしたデバッグでは、イスラエルの要素で地獄に陥ります。)

Linuxでは、パフォーマンスガバナーと呼ばれるまったく同じ問題が発生します。 ガバナーをパフォーマンスのようなものに切り替えるだけでなく、アフィニティゲームなどのウォームアップも役立ちます。

あなたにぴったりのベンチマーク。

Source: https://habr.com/ru/post/J113682/


All Articles