メモリアドレスからキャッシュ位置が1つに決まるキャッシュ配置方式
ダイレクトマップ方式とは、主記憶(メインメモリ)のあるブロックをキャッシュのどの行に置くかが、アドレスから機械的に1つに決まるキャッシュ配置方式のことです。キャッシュ=CPU のそばにある小さく速い記憶、ブロック=主記憶をひとまとまりにした単位のことです。
位置の決め方はとても単純で、キャッシュ位置 = アドレス(ブロック番号) mod キャッシュサイズ(行数)です。割り算の余りを使うので、同じブロックは必ず同じ行に入ります。上のツールでスライダーを動かすと、アドレスのインデックス部が示す行が1つに定まる様子を確認できます。
身近な例で言うと、下駄箱(くつ箱)の番号が出席番号で固定されているようなものです。出席番号10番の人は必ず10番の箱を使い、空いている箱を自由に選ぶことはできません。探すときは決まった箱だけ見ればよいので速い反面、同じ箱を使う人どうしはぶつかります。
位置を決めるために、アドレスを3つの部分に分割します。アドレスのビットの並びは、上位から順に次のようになります。
・タグ部:同じ行を使う複数のブロックを区別する印。行に記録しておき、ヒット判定で照合する
・インデックス部:どのキャッシュ行に入るかを直接示す番号
・オフセット部:ブロック内の何バイト目かを示す位置
例: アドレス 010100 を分割(行数 4)
─────────────────────
タグ 010 | インデックス 10 | オフセット 0
→ インデックス 10(2) = 2 → 必ず「行2」に入る
ヒット判定の手順は次のとおりです。まずインデックス部で行を1つに絞り、その行に記録されているタグと、アドレスのタグ部を照合します。タグが一致すればヒット、一致しなければミスです。1行だけ見ればよいので、照合は1回で済み、回路が単純で高速になります。
上のツールの「アドレスを分割して試す」スライダーを動かすと、どのアドレスがどの行に入るかが一目で分かります。インデックス部が同じアドレスは、タグ部が違っても必ず同じ行に入る点に注目してください。
「位置が1つに固定される」という性質が、ダイレクトマップの利点にも欠点にもなります。両面を整理しましょう。
最大の欠点は衝突(コンフリクトミス)です。たまたまインデックス部が同じになる2つのブロックを交互にアクセスすると、ほかの行が空っぽでも、その1行を取り合って毎回追い出しが起きます。上のツールの最後で、タグ違いの別ブロックが同じ行を上書きする様子を確認できます。
この衝突を緩和するために、行に少し置き場所の自由を持たせたのがセットアソシアティブ方式、完全に自由にしたのがフルアソシアティブ方式です。ダイレクトマップは「速いが衝突しやすい」極端な一方の方式だと位置づけられます。
結論:ダイレクトマップでは、インデックス部(アドレスをキャッシュ行数で割った余り)が同じになるブロックは、必ず同じ行に入ることが決まっているからです。他の行が空いていても「別の行を使う」という選択肢がありません。
具体例で見てみましょう。キャッシュが4行のとき、キャッシュ行 = ブロック番号 mod 4 で決まります。
・ブロック0:0 mod 4 = 0 → 行0に入る
・ブロック4:4 mod 4 = 0 → 行0に入る(被る!)
・ブロック8・12・16…:すべて行0に入る(mod 4 の余りが0)
身近な例で言うと、出席番号が「1番・5番・9番…」のように4の倍数ずれた生徒は、全員同じ番号の下駄箱を使わなければならないルールと同じです。空いている箱が隣にあっても使えず、毎回「今日の当番」が前の人を追い出します。ダイレクトマップの衝突はまさにこの状況です。
ヒット率(=キャッシュで見つかった回数 ÷ 総アクセス回数)が高いほど、CPUが主記憶を待つ時間が減り、コンピュータ全体が速くなります。ダイレクトマップでヒット率を上げるには、主に2つのアプローチがあります。
・キャッシュ容量を増やす:行数が増えればインデックスの種類が増え、同じ行に入るブロックが減って衝突しにくくなる
・アクセスの局所性を活かす:プログラムは短い時間に近い番地を繰り返しアクセスする傾向(局所性)がある。この傾向が強いほどキャッシュに残っている確率が上がりヒットしやすい
なぜ局所性があるとヒットしやすいのか。プログラムはループ(繰り返し処理)や配列(連続するデータの並び)を多用します。繰り返すたびに同じ番地へアクセスするので、1回目にキャッシュへ読み込まれたデータが2回目・3回目にもそのままヒットします。ダイレクトマップでも、衝突さえ起きなければこの恩恵を最大限受けられます。逆に衝突が多いアクセスパターンでは局所性の恩恵が消えてしまうのが、ダイレクトマップの泣き所です。