L2キャッシュ完全ガイド:仕組み・性能指標・実践的最適化テクニック

L2キャッシュとは

L2キャッシュ(レベル2キャッシュ、L2 cache)は、CPUのキャッシュ階層の中間に位置する高速メモリ領域です。主にコア内でのデータアクセスの遅延を低減し、L1キャッシュのミス時にL3キャッシュやメインメモリ(DRAM)へアクセスする回数を減らす役割を担います。L1が提供する超低レイテンシと小容量、メインメモリが提供する大容量と高レイテンシの間をつなぐ「容量とレイテンシのバランス」を取るのがL2キャッシュです。

基本的な役割と階層内の位置付け

典型的なモダンCPUでは、キャッシュは多段構成(L1 → L2 → L3 → メインメモリ)になっています。L1はコアごとに最も小さく最速(命令・データ分離が多い)、L2はL1より容量が大きくやや遅い、L3はさらに大容量で共有されることが多い、というのが一般的な設計です。L2はL1のミスによる「ミスペナルティ」を低減するため、L1ミス時の第1のフォールバックとして機能します。

構造と主な特性

  • 容量(サイズ): モダンCPUではコアあたり数百KBから1MB程度が一般的です。例として、Intelの一部マイクロアーキテクチャでは256KB/コア、AMD Zen世代では512KB/コアといった設計が見られます(世代や製品で差があります)。
  • ラインサイズ(キャッシュライン): ほとんどのCPUで64バイトがデファクトスタンダードです。キャッシュはライン単位で読み書きされます。
  • 連想度(アソシアティビティ): フルアソシアティブは高コストなため、セットアソシアティブ(例:4-way、8-way)が主流です。連想度は衝突ミスの発生率に影響します。
  • アクセスレイテンシ: コアや世代に依存しますが、一般的にL1が数サイクル(例: 3–5サイクル)、L2はそれより長い10–20サイクル程度、L3は数十サイクル、メインメモリは数百サイクルというオーダー感です(あくまで代表値)。
  • 書き込みポリシー: write-back(遅延書き戻し)とwrite-through(即時書き込み)があり、モダンCPUでは帯域効率を重視してL2はwrite-backが多いです。write-allocate(書き込みで不足行が来た場合に行を割り当てる)の採用も一般的です。
  • 包含性(Inclusive / Exclusive / Non-inclusive): L2がL1の内容を必ず包含する(inclusive)設計もあれば、L1とL2で重複が起きないexclusive設計や中間のnon-inclusive設計もあります。包含性はコヒーレンシや総キャッシュ容量の効率に影響します。

キャッシュ整合性(コヒーレンシ)とプロトコル

複数のコアと複数のキャッシュ階層が存在する環境では、キャッシュラインの一貫性を保つためのプロトコルが必要です。代表的なのはMESI(Modified, Exclusive, Shared, Invalid)やその拡張(MESIFなど)で、これによりコア間での読み書き状態を管理します。L2はしばしばL1の状態遷移に関与し、あるコアでの修正(Modified)があれば他のコアはInvalidにする動作が発生します。

置換ポリシーとプレフェッチ

キャッシュが満杯になった際にどの行を追い出すかを決める置換ポリシー(LRU、Pseudo-LRU、Randomなど)は、ヒット率に大きな影響を与えます。L2では実用に耐える低コストな擬似LRUがよく使われます。また、ハードウェアプリフェッチャ(次にアクセスされそうな行を先読みする機構)をL2近傍に置くことで、メモリアクセスの隠蔽を図ることが多く、連続アクセスに対して効果を発揮しますが、誤予測があると帯域や有効容量を浪費します。

物理/仮想インデックス、エイリアシング、ページカラーリング

キャッシュのインデックス付け(どのセットへ格納するか)は物理アドレスに基づく場合と仮想アドレスに基づく場合があります。L2は多くの場合物理インデックス/物理タグ(PIPT)で実装されますが、アドレス変換(TLB)との相互作用でエイリアシング(同じ物理アドレスが異なる仮想アドレスで別々にキャッシュされる問題)が生じることがあり、メモリアロケーション・ページカラーリングなどの手法でこれを軽減できます。OSやランタイムによるページ割当の工夫でキャッシュ効率を改善できます。

マルチコア環境とL2の配置(共有 vs プライベート)

マルチコアCPUでは、L2がコアごとのプライベートキャッシュになっている設計と、複数コアで共有される設計があります。プライベートL2は局所性に優れ、コヒーレンシ関連の通信はL3やインターコネクトを経由します。共有L2はコア間でデータ共有が多いワークロードに有利ですが、帯域や競合の影響を受けやすくなります。設計者はコア数や想定ワークロードに応じて最適な配置を選択します。

パフォーマンス指標と計測方法

キャッシュの評価は主にヒット率(hit rate)、ミス率(miss rate)、ミスペナルティ(miss penalty)、スループット(bandwidth)で行います。実際の測定にはCPUのパフォーマンスカウンタ(Linuxのperf、Intel VTune、PAPIなど)を用い、L1/L2ミス数やメモリ階層別の事件数を把握します。プロファイリングにより、どのコードパスがL2ミスを引き起こしているかを特定して最適化を行います。

ソフトウェア側での最適化テクニック

  • データ局所性を高める:配列アクセスを連続的にしたり、ループブロッキング(タイル化)でデータを働きセットに収める。
  • 構造体のレイアウト最適化:必要なデータを近接させ、パディングやアラインメントを調整してキャッシュラインの無駄を減らす。
  • プリフェッチ命令の活用:ハードウェアプリフェッチだけで足りないケースでソフトウェアプリフェッチを用いる。
  • False sharingの回避:複数スレッドが同じキャッシュラインを書き換えないように配置を工夫する。
  • メモリ確保の工夫:大きなデータ構造をページアライメントし、必要ならページカラーリングやHuge Pagesを利用する。

実装例とアーキテクチャ別の傾向

アーキテクチャによってL2の設計は異なります。一般にサーバー向けは大容量で共有L3とのバランスを重視し、モバイル向けは省電力・面積重視で各コアのL2を小さめにする傾向があります。世代が進むにつれて、L1は小容量・超低レイテンシ、L2は容量と帯域の拡大、L3はより大きな共有キャッシュというトレンドが見られます。具体的なサイズやレイテンシはマイクロアーキテクチャに依存するため、最適化時は対象プラットフォームのドキュメントやベンチマークを参照してください。

設計トレードオフ

L2の設計には必ずトレードオフがあります。容量を増やせばヒット率は上がるがレイテンシや消費電力、チップ面積が増える。逆に低レイテンシ化を重視すると容量や帯域が犠牲になります。さらに連想度を増やすと衝突ミスは減るが検索回路が複雑化して遅延や消費電力が増えます。設計者はターゲットワークロード(シングルスレッド性能、並列性能、モバイル消費電力など)を踏まえて最適点を探ります。

まとめ

L2キャッシュはCPUのメモリ階層における重要な中間バッファで、L1のミスを減らしメインメモリへのアクセス回数を抑えることで全体性能に大きく寄与します。サイズ、連想度、置換ポリシー、包含性、プレフェッチ戦略など多くの設計変数があり、アーキテクチャやワークロードによって最適解は変わります。ソフトウェア側ではデータ局所性の改善やプリフェッチの活用、False sharing回避などでL2効率を高められます。実運用ではパフォーマンスカウンタでボトルネックを特定し、ターゲットプラットフォームに合った最適化を行うことが重要です。

参考文献