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

前回の投稿からサンプルをダウンロードしました。開始から開始までの時間は、最大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では、パフォーマンスガバナーと呼ばれるまったく同じ問題が発生します。 ガバナーをパフォーマンスのようなものに切り替えるだけでなく、アフィニティゲームなどのウォームアップも役立ちます。



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



All Articles