私のコードは次のようん:ビジーループは、待ち時間クリティカルな計算を遅く
- は(以下役に立たないと呼ばれる)いくつかの長時間にわたる激しい計算
- を行い、小さな待ち時間のクリティカルなタスクに
レイテンシが重要なタスクを実行するのに要する時間は、長時間実行されている場合にはそれがない場合よりも高いことがわかります。ここで
いくつかのスタンドアロンC++コードこの効果を再現することである:1億USELESS
セットで-O3
してコンパイルする場合
#include <stdio.h>
#include <stdint.h>
#define LEN 128
#define USELESS 1000000000
//#define USELESS 0
// Read timestamp counter
static inline long long get_cycles()
{
unsigned low, high;
unsigned long long val;
asm volatile ("rdtsc" : "=a" (low), "=d" (high));
val = high;
val = (val << 32) | low;
return val;
}
// Compute a simple hash
static inline uint32_t hash(uint32_t *arr, int n)
{
uint32_t ret = 0;
for(int i = 0; i < n; i++) {
ret = (ret + (324723947 + arr[i]))^93485734985;
}
return ret;
}
int main()
{
uint32_t sum = 0; // For adding dependencies
uint32_t arr[LEN]; // We'll compute the hash of this array
for(int iter = 0; iter < 3; iter++) {
// Create a new array to hash for this iteration
for(int i = 0; i < LEN; i++) {
arr[i] = (iter + i);
}
// Do intense computation
for(int useless = 0; useless < USELESS; useless++) {
sum += (sum + useless) * (sum + useless);
}
// Do the latency-critical task
long long start_cycles = get_cycles() + (sum & 1);
sum += hash(arr, LEN);
long long end_cycles = get_cycles() + (sum & 1);
printf("Iteration %d cycles: %lld\n", iter, end_cycles - start_cycles);
}
}
、3回の反復はそれぞれ、588、4184を取り、536サイクル。 USELESS
を0に設定してコンパイルすると、繰り返しはそれぞれ394,358、および362サイクルでした。
なぜこれが(特に4184サイクル)起こっているのですか?私は、強烈な計算によって引き起こされたキャッシュミスやブランチ誤予測を疑った。しかし、激しい計算がなければ、レイテンシ・クリティカルなタスクの0回目の反復はかなり速いので、私はコールド・キャッシュ/分岐予測子が原因だとは思わない。
私は 'get_cycles()'が内部ループの前に並べ替えられていると確信しています。アセンブラを見てみてください。 – Jarod42
4184外れ値は、OSや他のプロセスのような、あなたのコントロールの何かが原因で発生する可能性があります。さらに、現代のマルチコア、マルチ周波数コンピュータでのrdtscの精度は不十分です。 – user4581301
@ Jarod42 - 確認しました。並べ替えられていません。 –