私は Cachegrind を使用して、libc なしでコンパイルされた静的プログラムのキャッシュ ミスの数を取得してい_start
ます (asm でメイン関数と exit syscall を呼び出すだけです)。プログラムは完全に決定論的であり、命令とメモリ参照は実行ごとに変化しません。キャッシュは、置換ポリシーとして LRU と完全に関連付けられています。
ただし、ミスの数が時々変化することに気付きました。より具体的には、別のディレクトリに移動するまで、ミスの数は常に同じです。
% cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./adpcm
...
==31352== I refs: 216,145,010
...
==31352== D refs: 130,481,003 (95,186,001 rd + 35,295,002 wr)
==31352== D1 misses: 240,004 ( 150,000 rd + 90,004 wr)
==31352== LLd misses: 31 ( 11 rd + 20 wr)
同じコマンドを何度も実行すると、同じ結果が得られます。しかし、別のディレクトリからこのプログラムを実行すると:
% cd ..
% cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./malardalen2/adpcm
...
==31531== I refs: 216,145,010
...
==31531== D refs: 130,481,003 (95,186,001 rd + 35,295,002 wr)
==31531== D1 misses: 250,004 ( 160,000 rd + 90,004 wr)
==31531== LLd misses: 31 ( 11 rd + 20 wr)
また、別のディレクトリからの結果も異なります。
また、Pin ツールを使用していくつかの実験を行いましたが、これを使用すると、異なる値を取得するためにディレクトリを変更する必要はありません。しかし、可能な値のセットは非常に限られているようで、Cachegrind とまったく同じです。
私の質問は、そのような違いの原因は何でしょうか?
私の最初のヒントは、私のプログラムがメモリ内で同じように配置されていないことです。その結果、以前の実行で同じ行に格納されたいくつかの変数はもうありません。これは、組み合わせの数が限られていることも説明できます。しかし、キャッシュグラインド(およびピン)は仮想アドレスを使用していたと思いますが、OS(Linux)は常に同じ仮想アドレスを提供していると思います。他のアイデアはありますか?
編集: LLd ミスの読み取りを推測できるように、プログラムは 31 の異なるキャッシュ ラインのみを使用します。また、キャッシュには 8 つのキャッシュ ラインしか含めることができません。したがって、実際の場合でも、キャッシュが 2 回目に既に読み込まれているという考えでは、違いを説明できません (最大で、L1 にとどまることができるのは 8 ラインのみです)。
編集 2: Cachegrind のレポートは、実際のキャッシュ ミス (パフォーマンス カウンターによって与えられる) に基づくものではなく、シミュレーションの結果です。基本的に、ミスの数をカウントするためにキャッシュの動作をシミュレートします。結果は一時的なものに過ぎないため、それはまったく問題なく、キャッシュ プロパティ (サイズ、結合性) を変更できます。
編集 3:私が使用しているハードウェアは、Linux 3.2 x86_64 上の Intel Core i7 です。コンパイル フラグは -static で、一部のプログラムでは -nostdlib (IIRC、私は今家にいません) です。