4

以下のコードを書き直して、配列のキャッシュ パフォーマンスを向上させる (キャッシュのミスを減らすことによって) 方法を考えてみました。

配列は行ごとに(順次)メモリに格納されることを認識しているため、ary[0][0]、ary[0][1]、ary[0][2]、....ary[1] [0]、ary[1][1]、ary[1][2]...ary[50][0]、ary[50][1]...ary[50][50]。ただし、この情報を使用して、ループを変更してキャッシュのパフォーマンスを向上させる方法を理解する方法がわかりません。

for (c = 0; c < 50; c++)
    for (d = 0; d < 50; d++)
        ary[d][c] = ary[d][c] + 1;
4

4 に答える 4

4

行のすべてのセルに一度にアクセスしたい場合は、2 つのループを逆にします。

for (d = 0; d < 50; d++)
    for (c = 0; c < 50; c++)
        ary[d][c] = ary[d][c] + 1;

あるいは

for (d = 0; d < 50; d++)
    int[] array = ary[d];
    for (c = 0; c < 50; c++)
        array[c] = array[c] + 1;

しかし、特に非常に小さなアレイでは、それが重大な影響を与えるか、まったく影響を与えるとは思えません。コードをシンプルで読みやすいものにします。事前に最適化しないでください。

于 2012-11-27T21:35:05.693 に答える
3

ループの順序を入れ替えます。arr[1][0]の直後にアクセスしていますarr[0][0]arr[1][0]は遠く離れていarr[0][1]ますが、 は次のアドレスにあります。

于 2012-11-27T21:36:38.047 に答える
1

パフォーマンスを向上させるために、キャッシュミスの数を最小限に抑える必要があります。キャッシュが失われるたびに、メモリアクセスと新しいブロックのキャッシュへのロードが発生します。このブロックには、必要な値だけでなく、メモリからの追加の隣接値も含まれています。ローカリティの原則を利用する必要があります。つまり、各メモリアクセスからできるだけ多くの値を使用します。観察で述べたように、配列は行ごとにメモリに格納されるため、配列を順番にトラバースすると、キャッシュミスの数が最小限に抑えられます。コードに戻るには、ループの順序を入れ替えます。

for (d = 0; d < 50; d++)
    for (c = 0; c < 50; c++)
        ary[d][c] = ary[d][c] + 1;

または、計算でインデックスを交換します。

for (c = 0; c < 50; c++)
    for (d = 0; d < 50; d++)
        ary[c][d] = ary[c][d] + 1;

2D配列を50*50サイズの1D配列として扱い、単一のforループを使用して最初から最後までスキャンすることもできます。

于 2012-11-27T21:45:10.167 に答える
0

キャッシュは、コード内の参照の局所性を独自に利用するように設計されているため、ループをスワップする以外はおそらく何もする必要はありません。つまり、最初の要素とそれに続くいくつかの要素 (空間的局所性) をキャッシュします。配列から取得し、しばらくの間キャッシュに保持します (一時的な局所性)。

ただし、一部のコンパイラではキャッシュを制御できます。たとえば、gcc には __builtin_prefetch があり、どのデータをプリフェッチするか、キャッシュに残すかどうかを制御できます。

— 組み込み関数: void __builtin_prefetch (const void *addr, rw, locality)

この機能は、データがアクセスされる前にキャッシュに移動することで、キャッシュ ミスのレイテンシを最小限に抑えるために使用されます。__builtin_prefetch への呼び出しを、すぐにアクセスされる可能性が高いメモリ内のデータのアドレスがわかっているコードに挿入できます。ターゲットがそれらをサポートしている場合、データ プリフェッチ命令が生成されます。プリフェッチがアクセスの十分前に行われる場合、データはアクセスされるまでにキャッシュ内に存在します。

そして、マニュアルには次の例が示されています。

for (i = 0; i < n; i++)
{
  a[i] = a[i] + b[i];
  __builtin_prefetch (&a[i+j], 1, 1);
  __builtin_prefetch (&b[i+j], 0, 1);
  /* ... */
}
于 2012-11-27T21:57:08.370 に答える