2016-09-13 6 views
2

私のコードは次のようん:ビジーループは、待ち時間クリティカルな計算を遅く

  1. は(以下役に立たないと呼ばれる)いくつかの長時間にわたる激しい計算
  2. を行い、小さな待ち時間のクリティカルなタスクに
を実行します。

レイテンシが重要なタスクを実行するのに要する時間は、長時間実行されている場合にはそれがない場合よりも高いことがわかります。ここで

いくつかのスタンドアロン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回目の反復はかなり速いので、私はコールド・キャッシュ/分岐予測子が原因だとは思わない。

+0

私は 'get_cycles()'が内部ループの前に並べ替えられていると確信しています。アセンブラを見てみてください。 – Jarod42

+0

4184外れ値は、OSや他のプロセスのような、あなたのコントロールの何かが原因で発生する可能性があります。さらに、現代のマルチコア、マルチ周波数コンピュータでのrdtscの精度は不十分です。 – user4581301

+0

@ Jarod42 - 確認しました。並べ替えられていません。 –

答えて

1

答えに私の投機的なコメントを移動:

あなたの忙しいループの実行中に、サーバー上の他のタスクは、L1キャッシュのキャッシュアウトさarrデータをプッシュしていることも可能である第一のメモリアクセスするようにhashでは、下位レベルのキャッシュからリロードする必要があります。計算ループがなければ、これは起こりません。計算ループの後に、arrの初期化を移動して、その効果を確認することができます。

関連する問題