メモリ階層と性能

C言語の2次元配列a[i][j]を上のように内側のループをjにして走査すると、内側をiにするより速くなりやすい。その理由はどれか。

for (i = 0; i < N; i++)
    for (j = 0; j < N; j++)
        sum += a[i][j];
  1. A行優先で格納されているため、連続したアドレスを順に読み、キャッシュラインを有効に使えるから
  2. Bコンパイラがループの中の加算をまとめて取り除き、計算そのものを実行時に省略してしまうから
  3. C内側をjにするとTLBを一切参照しなくなり、仮想アドレスから物理アドレスへの変換が不要になるから
答えと解説を見る

正解:A. 行優先で格納されているため、連続したアドレスを順に読み、キャッシュラインを有効に使えるから

C言語の2次元配列は行優先(row-major)で格納され、a[i][0]、a[i][1]…がメモリ上に隣り合います。内側をjにすると連続したアドレスを順に読むため、1回のミスで読み込んだ64バイトのキャッシュラインの残りもすぐ使われます。内側をiにすると1行分ずつ離れたアドレスを飛び飛びに読み、ラインのごく一部しか使わないうちに追い出されやすくなります。TLBは使い続けており、アドレス変換が不要になるわけではありません。

  • A. 正しい。連続したアドレスを読むので、読み込んだラインの全体を使えます。
  • B. 加算は省略されず、どちらの順でも同じ計算をします。
  • C. TLBは引き続き使われ、アドレス変換も行われます。
この分野を解く 分野ページへ

メモリ階層と性能のほかの問題

  1. アドレスが32ビット、容量32 KB、ラインサイズ64バイトのダイレクトマップ方式のキャッシュで、タグは何ビットになるか。
  2. アドレスが32ビット、容量32 KB、ラインサイズ64バイトの4ウェイ・セットアソシアティブ方式のキャッシュのセット数はいくつか。
  3. フルアソシアティブ方式のキャッシュで、アドレスのうちインデックス(セットを選ぶ部分)に使うビット数はどれか。
  4. L1キャッシュのヒット時間が1 ns、ミス率が5%、L2キャッシュのヒット時間が10 ns、L2のローカルミス率が20%、主記憶のアクセス時間が100 nsのとき、平均メモリアクセス時間はいくらか。
  5. ダイレクトマップ方式のキャッシュで、2つの配列の要素が同じキャッシュの位置に対応し、交互にアクセスするたびに互いを追い出し合っている。このミスの分類はどれか。