6

私の考えは、命令キャッシュの制限の影響を示すエレガントなコード例を提供することでした。私は、テンプレートメタプログラミングを使用して、大量の同一機能を作成する以下のコードを書いた。命令キャッシュの制限の影響を実証する方法

volatile int checksum; 
void (*funcs[MAX_FUNCS])(void); 

template <unsigned t> 
__attribute__ ((noinline)) static void work(void) { ++checksum; } 

template <unsigned t> 
static void create(void) { funcs[t - 1] = &work<t - 1>; create<t - 1>(); } 

template <> void create<0>(void) { } 

int main() 
{ 
    create<MAX_FUNCS>(); 

    for (unsigned range = 1; range <= MAX_FUNCS; range *= 2) 
    { 
     checksum = 0; 
     for (unsigned i = 0; i < WORKLOAD; ++i) 
     { 
      funcs[i % range](); 
     } 
    } 

    return 0; 
} 

外部ループは、ジャンプテーブルを使用して呼び出されるさまざまな関数の量を変化させます。各ループパスに対して、WORKLOAD関数を呼び出すために要した時間が測定されます。今、結果は何ですか?次の図は、使用された範囲に対する関数呼び出しあたりの平均実行時間を示しています。青色の線は、Core i7マシンで測定されたデータを示しています。赤線で示した比較測定は、Pentium 4マシンで行った。しかし、それは、これらの行を解釈することになると、私は何とか苦労しているように見える...

chart

範囲内のすべての機能のための総メモリ消費量を超え場所を正確に区分的に一定赤い曲線の唯一のジャンプが起こりますテストされたマシン上の1つのキャッシュ・レベルの容量。専用の命令キャッシュはありません。ただし、非常に小さい範囲(この場合は4未満)では、機能の量によって実行時間が増加します。これは分岐予測の効率に関係するかもしれませんが、この場合は関数呼び出しが無条件のジャンプに減少するため、ブランチングのペナルティがあるかどうかはわかりません。

青いカーブは、まったく異なる動作をします。ランタイムは小領域では一定であり、その後は対数を増加させる。しかし、より広い範囲については、曲線は一定の漸近線に再び近づいていると思われる。両方の曲線の質的差異はどのくらい正確に説明できますか?

私は現在、GCC MinGW Win32 x86 v.4.8.1とg++ -std=c++11 -ftemplate-depth=65536を使用しており、コンパイラの最適化は行っていません。

ご協力いただければ幸いです。私はまた、実験そのものをどのように改善するかについてのアイデアにも興味があります。前もって感謝します!

答えて

1

まず、この問題にどのように近づいてきたかが本当に好きだと言いましょう。これは、意図的なコード膨張の本当にきれいな解決策です。ただし、テストにはまだいくつかの問題がある可能性があります。

  1. また、ウォームアップ時間も測定します。あなたはあなたのタイムチェックをどこに置いたかを示していませんでしたが、それが内部ループの周りにあるならば、最初に範囲/ 2に達するまで、以前の外部反復のウォームアップを楽しむことができます。代わりに、暖かいパフォーマンスのみを測定します。 - 各内部反復を数回実行し(中間に別のループを追加します)、1-2回後にタイムスタンプを取得します。

  2. あなたのメジャーキャッシュレベルはいくつかありますが、L1キャッシュはグラフが終わる32kだけです。これが "範囲"でカウントされていると仮定しても、各関数は〜21バイト(少なくともgcc 4.8.1以上)なので、最大で256KBに達するので、L2のサイズをスクラッチします。

  3. CPUモデルを指定していません(i7は現在市場に4世代以上あり、Haswell、IvyBridge、SandyBridge、Nehalem)。その違いはかなり大きく、たとえばSandybrigeには複雑なストレージルールと条件があるため、追加のuop-cacheなどがあります。あなたのベースラインも事態を複雑にしています.P4にはあらゆる種類のパフォーマンスに影響を与える可能性のあるトレースキャッシュが正しく記憶されています。可能であれば、それらを無効にするオプションをチェックする必要があります。

  4. TLBを忘れないでください - このようなきめ細かなコードではおそらく役割を果たさないかもしれませんが、固有の4kページの数はITLB(128エントリ)を超えてはならず、あなたのOSが物理的なコードページをITLBの衝突を避けるために十分に広げていない場合には、衝突を開始する可能性があります。

関連する問題