std :: chronoを少し試してみるために次のプログラムを作成しました。
#include <iostream>
#include <chrono>
int main(int argc, char** argv) {
const long iterationCount = 10000;
long count = 0;
for(long i = 0; i < iterationCount; i++) {
auto start = std::chrono::high_resolution_clock::now();
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
auto end = std::chrono::high_resolution_clock::now();
auto timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
std::cout << timeTaken << " " << std::endl;
}
}
コンパイラの最適化を有効にせずにG ++を使用してこれをコンパイルしました。
g++ chrono.cpp -o chrono
その後、このプログラムを数回実行したところ、興味深いパターンが得られました。最初の500〜1000回の反復では、プログラムは残りの反復よりも約7〜8倍遅く実行されます。
このプログラムの出力例は次のとおりです:https://pastebin.com/tUQsQEAQ
ランタイムでこの不一致の原因は何ですか?私の最初の反応はキャッシュでしたが、それはすぐに飽和状態になりませんか?
重要な場合、私のオペレーティングシステムはUbuntu 18.04で、g ++のバージョンは7.3.0です。
マイクロアーキテクチャの実装で定義された時間が経過した後、CPUが同じ火力発電のヘッドルームを見つけることができる場合、周波数スケーリングが開始され、要求の厳しいコアのクロックが最大(TDPの制限内)まで高速化されます。
Intelの実装はターボブーストと呼ばれます。
システムで周波数スケーリングを無効にすると(たとえば、sudo cpupower frequency-set --governor performance
-cpupower
がcpupowerutils
パッケージに含まれている場合)、各反復の時間はほぼ同じになります。
ループ自体は非常に簡単に予測できます。ループコントロールの最後に1つだけではなく、わずかな予測ミスしか期待できません。C++ライブラリ内のコードは予測が難しい可能性がありますが、それでもそれほど時間はかかりません( BPUがコードに追いつくための1000回の反復)。
したがって、分岐予測の誤予測を排除できます。
多かれ少なかれ同じことがIキャッシュにも当てはまります(C ++ライブラリの実装が変数の使用に重きを置いていない限り、Dキャッシュの使用はほとんどありません)。
コードは、L1-Iに収まるように十分に小さくする必要があり、ほとんどの場合、DSBにも収まります。
L1-私は、解決するのに1000回の反復を必要とせず、キャッシュに重いセットの競合がある場合、1000回の反復後に消えない一般的な速度低下として表示されます。
一般的に言えば、CPUが最初にキャッシュ(データ、命令、TLB)をいっぱいにするため、ループに含まれる依存関係チェーンの2回目の反復からコードがより高速に実行されることは既知の効果です。
CPUのリソースが不足すると、最終的には再び速度が低下する可能性があります。たとえば、ポートのプレッシャーが大きい場合(たとえば、同一の制限ポートの長い遅延命令が多数ある場合)、RSがFEのストールをいっぱいにする可能性があります。 MOB / SB / LBを埋める大量のロード/ストアまたはBOBを埋める大量のジャンプ。
ただし、これらの効果は非常に迅速に開始され、コードの実行時間を支配するようになります。
この場合、速度低下は非常に遅く(CPU時間で)発生するため、ターボブーストなどのオンデマンドプロセスについて考えることが望ましいです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加