9

Ulrich Drepper のWhat Every Programmer Should Know About Memory pdf を読んでいます。パート 6 の冒頭にコード フラグメントがあります。

#include <emmintrin.h>
void setbytes(char *p, int c)
{
    __m128i i = _mm_set_epi8(c, c, c, c,
    c, c, c, c,
    c, c, c, c,
    c, c, c, c);
    _mm_stream_si128((__m128i *)&p[0], i);
    _mm_stream_si128((__m128i *)&p[16], i);
    _mm_stream_si128((__m128i *)&p[32], i);
    _mm_stream_si128((__m128i *)&p[48], i);
}

そのすぐ下にそのようなコメントがあります:

ポインターpが適切に配置されていると仮定すると、この関数を呼び出すと、アドレス指定されたキャッシュ ラインのすべてのバイトが に設定されますc。書き込み結合ロジックは、生成された 4 つの movntdq 命令を確認し、最後の命令が実行された後にのみメモリの書き込みコマンドを発行します。要約すると、このコード シーケンスは、キャッシュ ラインが書き込まれる前に読み取られることを回避するだけでなく、すぐには必要とされない可能性のあるデータでキャッシュが汚染されることも回避します。

私を悩ませているのは、関数へのコメントで「アドレス指定されたキャッシュラインのすべてのバイトを c に設定する」と書かれていることですが、ストリーム組み込み関数について理解していることから、キャッシュをバイパスします-キャッシュの読み取りもキャッシュの書き込みもありません。このコードはキャッシュ ラインにどのようにアクセスしますか? 2 番目の太字の部分は、関数が「キャッシュ ラインが書き込まれる前に読み取られるのを回避する」という、似たようなことを言っています。上記のように、キャッシュがいつどのように書き込まれるかはわかりません。また、キャッシュへの書き込みの前にキャッシュ書き込みを行う必要がありますか? 誰かが私にこの問題を明確にしてもらえますか?

4

3 に答える 3

3

メモリに書き込むときは、キャッシュ ラインを部分的にしか書き込まない場合に備えて、書き込むキャッシュ ラインを最初にキャッシュにロードする必要があります。

メモリに書き込むと、ストアはストア バッファーにグループ化されます。通常、バッファがいっぱいになると、キャッシュ/メモリにフラッシュされます。通常、ストア バッファの数は少ない (~4) ことに注意してください。アドレスへの連続書き込みは、同じストア バッファを使用します。

非一時的なヒントを使用したスト​​リーミング読み取り/書き込みは、通常、キャッシュの汚染を減らすために使用されます (多くの場合、WC メモリを使用)。アイデアは、これらの命令が使用するために、CPU でキャッシュ ラインの小さなセットが予約されているということです。キャッシュ ラインをメイン キャッシュにロードする代わりに、この小さなキャッシュにロードします。

コメントは、次の動作を想定しています (ただし、ハードウェアが実際にこれを行うという参照は見つかりません。測定する必要があるか、確実なソースが必要であり、ハードウェアによって異なる可能性があります): - ストア バッファーがいっぱいであることを CPU が確認すると非テンポラル書き込みはメイン キャッシュをバイパスするため、キャッシュ ラインにアラインされている場合は、直接メモリにフラッシュします。

これが機能する唯一の方法は、フラッシュされた後に実際に書き込まれたキャッシュ ラインとストア バッファーのマージが発生する場合です。これは公正な仮定です。

書き込まれたキャッシュ ラインが既にメイン キャッシュにある場合、上記のメソッドはそれらも更新することに注意してください。

非一時的な書き込みの代わりに通常のメモリ書き込みが使用された場合、ストア バッファーのフラッシュによってメイン キャッシュも更新されます。このシナリオでは、メモリ内の元のキャッシュ ラインの読み取りも回避される可能性が十分にあります。

一時的ではない書き込みで部分的なキャッシュ ラインが書き込まれる場合、おそらくキャッシュ ラインはメイン メモリ (または存在する場合はメイン キャッシュ) からフェッチする必要があり、事前にキャッシュ ラインを読み取っていないと非常に遅くなる可能性があります。通常の読み取りまたは非一時的な読み取り (別のキャッシュに配置されます)。

通常、非テンポラル キャッシュのサイズは 4 ~ 8 キャッシュ ライン程度です。

要約すると、ストア バッファもたまたまいっぱいになるため、最後の命令が書き込みを開始します。ハードウェアは、ストア バッファーが連続しており、キャッシュ ラインに整列していることを認識しているため、ストア バッファー フラッシュでは、書き込まれたキャッシュ ラインの読み取りを回避できます。非一時的な書き込みヒントは、書き込まれたキャッシュ ライン IF がメイン キャッシュに入力されるのを回避するためだけに機能し、それがメイン キャッシュにまだ含まれていなかった場合にのみ機能します。

于 2016-05-01T20:09:57.487 に答える
1

これは部分的に用語の問題だと思います.Ulrich Drepperの記事から引用した一節は、キャッシュされたデータについて話しているのではありません. 整列された64Bブロックに対して「キャッシュライン」という用語を使用しているだけです。

これは正常な動作であり、キャッシュ ラインのサイズが異なるさまざまなハードウェアについて話す場合に特に役立ちます。(以前の x86 CPU、最近では PIII には 32B のキャッシュ ラインがあったため、この用語を使用すると、そのマイクロアーチ設計の決定を議論にハードコーディングすることを回避できます。)

データのキャッシュ ラインは、現在どのキャッシュでもホットでない場合でもキャッシュ ラインのままです。

于 2016-05-02T04:25:30.927 に答える