オンチップキャッシュ完全ガイド:L1〜L3の構造・置換・最適化とセキュリティ対策

オンチップキャッシュとは何か — 基本定義

オンチップキャッシュ(on-chip cache)は、CPUコアやSoC(System on Chip)ダイの内部に直接組み込まれた高速なメモリ(通常はSRAM)です。主にプロセッサと主メモリ(DRAM)の速度差を埋めるために設けられ、アクセス遅延(レイテンシ)とメモリ帯域の改善を目的とします。オンチップにあることで、電気的距離が短く、オフチップ(パッケージ外や基板上)より低遅延・低消費電力で動作します。

キャッシュの階層と配置

一般的なCPUでは複数レベルのキャッシュ階層が存在します。代表的な構成は以下の通りです。

  • L1キャッシュ:コアごとに独立(インストラクションキャッシュとデータキャッシュに分かれることが多い)。最も高速で容量は小さい(典型は16〜64KB程度)。
  • L2キャッシュ:コアごとに専有のものや、複数コアで共有する設計がある。容量は数十KB〜数MB、L1より遅いが容量は大きい。
  • L3キャッシュ(LLC):多コアで共有されることが多く、容量は数MB〜数十MB。設計によってはオンチップ(同ダイ)に実装され、近年のXeon/EPYCやRyzenなどではオンダイの共有キャッシュが一般的になっている。

「オンチップ」という表現は“ダイ上に実装されている”ことを指し、オフチップL2やL3(かつての外付けキャッシュや基板実装)は含みません。設計や世代により、どの階層までがオンチップかは異なります。

キャッシュの基本構造と用語

キャッシュは「ライン(キャッシュライン、通常は64バイトが多い)」を単位にデータを格納します。主な分解要素は次の通りです。

  • タグ(Tag):メモリアドレスの上位ビットで、該当ラインがキャッシュ内のどの位置のデータかを識別する。
  • インデックス(Index):キャッシュセットを選ぶためのビット。
  • オフセット(Offset):ライン内のバイト位置を選ぶビット。

マッピング方式には主に次がある:

  • 直接マップ(Direct-mapped):各ラインが1つの位置に固定。実装単純だが衝突が起きやすい。
  • セット連想(Set-associative):複数行が1セットにまとまる(例:4-way)。性能と実装コストのバランスを取った一般的方式。
  • フルアソシアティブ(Fully-associative):任意位置に格納可能だが検索コストが高い、通常は小容量の特別用途(Victim cache等)に使われる。

書き込みと置換の振る舞い

キャッシュの書き込みには代表的に次の方針がある:

  • Write-through:キャッシュへの書き込みと同時に下位メモリにも書き込む。データ整合性は分かりやすいが帯域を使う。
  • Write-back(Write-back cache):キャッシュ内のみを書き込み、ある条件で(ライン置換時など)下位メモリへ書き戻す。帯域効率が良いが、コヒーレンシや障害時の扱いが複雑。

置換アルゴリズムはLRU(最近最少使用)やその近似、ランダム、FIFOなどが利用されます。高連想度や大容量キャッシュでは完全LRUはコストが高く、擬似LRU(pseudo-LRU)がよく使われます。

仮想アドレスと物理アドレス:インデックス/タグの設計

キャッシュは「仮想インデックス/仮想タグ(VIVT)」「仮想インデックス/物理タグ(VIPT)」「物理インデックス/物理タグ(PIPT)」など設計が分かれます。VIPTはL1で広く使われ、ページサイズやキャッシュサイズ・アソシアティビティに依存してチューニングされます。仮想インデックスを使うと同時にTLB(Translation Lookaside Buffer)と並列でアクセスしやすいが、同一物理ページを異なる仮想アドレスで参照する「同義語(aliasing)」問題に注意が必要です。

マルチコア環境とキャッシュコヒーレンシ

コアが複数ある場合、各コアのローカルキャッシュ間でデータ整合性(コヒーレンシ)を保つ必要があります。一般的なプロトコルにMESI(Modified, Exclusive, Shared, Invalid)や拡張版のMOESI等があります。これらはキャッシュラインの状態を管理し、他のコアとデータをやり取りする際の振る舞いを規定します。

また、キャッシュ階層について「包括性(inclusive)」「排他性(exclusive)」「非包括(non-inclusive)」という設計方針があり、どの階層に同一データが存在するかによりメモリ操作や置換戦略が変わります。

性能への影響:ヒット率・ミス遅延・帯域

キャッシュ性能は主にヒット率(キャッシュ内に要求データがある割合)とミス時のペナルティ(ミス遅延)で決まります。命令実行の平均メモリアクセス時間(AMAT)は簡略的に "AMAT = L1ヒット時間 + L1ミス率 × L1ミスペナルティ" と表せます。したがって、L1の低レイテンシとL2/L3の高ヒット率のバランスが重要です。具体的なサイクル数は設計や世代で大きく変わるため一概には言えませんが、L1は1〜数サイクル、L2は数〜十数サイクル、L3は数十サイクルという「漠然とした目安」がしばしば用いられます。

ハードウェア実装のポイント

オンチップキャッシュはSRAMセル(一般に6トランジスタ構成)で実装され、面積と消費電力のトレードオフが設計上の大問題です。大容量にすると配線遅延やセル読み出し電力が増え、さらにセット選択やタグマッチング回路の複雑さも問題になります。そのため、キャッシュはバンク化(複数の独立バンクへ分割)、パイプライン化、複数ポート化(同時アクセス)などの工夫がなされます。また、ラインフェッチ時のバス幅やバースト幅、書き込みバッファ(write buffer)、リード/ライトサーボ(read/write port)設計も重要です。

最適化とソフトウェアの工夫

プログラマやコンパイラはキャッシュ特性を利用して性能を改善できます。代表的な手法:

  • データ局所性の改善:ループの順序を変える、データ構造を線形配列にするなどで空間局所性・時間局所性を高める。
  • ブロッキング/タイル法:大きな行列演算をキャッシュに収まるブロックに分ける。
  • データアラインメント:キャッシュライン境界を意識した配置で、余分なラインミスを防ぐ。
  • プリフェッチ:ハードウェアプレフェッチャやソフトウェアプリフェッチ命令で将来必要なデータを事前に読み込む。

これらは科学計算やデータベース、ゲーム開発などで特に重要です。Agner Fogの最適化ガイドなどには具体的テクニックがまとまっています。

観測とデバッグ:測定手法

キャッシュの挙動はプロファイラやハードウェアイベントカウンタ(Linuxのperfなど)で測定できます。シミュレータ(Intel PIN, ValgrindのCachegrind)やマイクロベンチマーク(ストライドアクセス、ランダムアクセスなど)を使ってヒット率・ミス率・遅延の特性を評価します。これにより、アルゴリズムやデータレイアウトの改善点が明らかになります。

セキュリティとサイドチャネル

オンチップキャッシュは性能向上の要である一方、タイミング差を利用したサイドチャネル攻撃(Flush+Reload、Prime+Probeなど)の対象になりやすいことが知られています。さらにSpectreやMeltdownのような投機実行に絡む脆弱性は、キャッシュを通じて機密データを漏えいさせる経路として悪用されました。これを受けてハードウェア側の緩和(スペクター対策)、OSやコンパイラの変更、アプリケーションレベルの対策が進められています。

今後の動向

近年は多コア化・キャッシュ階層の深度化・大容量共有キャッシュの採用が進んでいます。特殊用途向けにオンチップでの高速キャッシュと大容量近接メモリ(HBMなど)を組み合わせる設計も増えています。一方で省電力化の要求が強く、キャッシュの電力管理(リーク電流対策、スリープモード、階層ごとの電源制御)やコンパクトな置換アルゴリズムの研究も盛んです。

まとめ

オンチップキャッシュはCPU性能を決定づける重要な設計要素です。低遅延・高帯域を実現するために、ラインサイズ、アソシアティビティ、階層構成、書き込みポリシー、コヒーレンシプロトコルなど多くの設計判断が関与します。ソフトウェア側でも局所性を意識した設計やプロファイリングによる最適化が効果を発揮します。同時に、セキュリティや省電力といった新たな要件にも対応していく必要があります。

参考文献