本連載はHisa Ando氏による連載「コンピュータアーキテクチャ」の初掲載(2005年9月20日掲載)から第72回(2007年3月31日掲載)までの原稿を再掲載したものとなります。第73回以降、最新のものにつきましては、コチラにて、ご確認ください。

プロセスごとの仮想空間の使用と、ページテーブルによる管理は、メモリの効率的な使用と、各ページにさまざまな属性を付け、使い方をチェックすることにより、安全性を高められる優れた方法であるが、キャッシュに対しては少なからぬ影響がある。

メモリエーリアス

プログラムの実行に伴うメモリアクセスは仮想アドレスで行われる。従って、TLBにより実アドレスに変換してキャッシュを参照する必要がある。しかし、これでは高速を要する1次キャッシュのアクセスがTLBをアクセスして実アドレスに変換し、その実アドレスでキャッシュをアクセスするという2段階となり、アクセス時間が長くなるという問題がある。

このため、仮想アドレスでキャッシュを引く(インデックスする)という方式が考えられた。実アドレスに変換してからキャッシュを引く方式では実(Physical)アドレスからインデックスを作るので、Physically Indexed (PI)と呼び、仮想アドレスのままでキャッシュを引く方式をVirtually Indexed (VI)と呼ぶ。

また、VI方式の場合は、キャッシュメモリのタグアレイに格納するアドレスも仮想アドレスとするVirtually Tagged (VT)方式とタグは実アドレスとするPhysically Tagged (PT)方式が考えられる。しかし、タグアレイの読出しとTLBを読出しての実アドレスへの変換は同時に並列に実行することが可能であり、処理時間的な損失無く実アドレスのタグを比較することができる。このためVTにするメリットは少なく、VIPT方式が一般的に使用されている。図9にPIPT方式のキャッシュアクセスと、VIPT方式のキャッシュアクセスの流れを示す。

  • PIPT方式とVIPT方式のキャッシュアクセスの流れ

    図9:PIPT方式とVIPT方式のキャッシュアクセスの流れ

PIPT方式は、キャッシュから見ると仮想アドレスは見えないので単純であるが、TLB(あるいはマイクロTLB)で実アドレスに変換する時間がオーバーヘッドとなり、折角のキャッシュが遅くなってしまうという問題がある。プロセサコアに内蔵される1次キャッシュではアクセス時間が重要であり、次に述べるように各種の工夫がなされているが、2次キャッシュ以下では、1次キャッシュのアクセスと並行してアドレス変換が行えるので、通常、PIPT方式が用いられる。

VI方式の場合、セットアソシアティブキャッシュの各wayのサイズがページサイズと同じかそれより小さい場合は、仮想空間と実空間アドレスの下位ビットは一致しているので、仮想アドレスからインデックスを求めても、実アドレスからインデックスを求めても同じものになるが、例えば、各wayのサイズを2ページ分にすると、仮想と実アドレスでインデックスの最上位ビットが異なる場合が存在しうる。このため、プロセス1である物理ページを、そのプロセスの仮想空間の偶数ページアドレスに割り付け、プロセス2で同じ物理ページをそのプロセスの奇数ページに割り当てた場合、同じデータがキャッシュ内で異なる場所に格納されることになり、同じ実アドレスであるのに、その内容をプロセス1が書き換えても、プロセス2では別のキャッシュラインをアクセスするので古い値のままとなり矛盾が生じてしまう。

これを避けるために、VI方式では各wayのサイズをページ(複数のページサイズをサポートする場合は、最小のページ)サイズとし、キャッシュ容量の増加は、もっぱらway数の増大で対応するとことになる。Intelプロセサの1次キャッシュはこの方式であり、Pentium 4では4KBページ×4wayで16KB、Pentium Mでは4KB×8wayで32KBである。しかし、way数をやたらに大きくすると多数のタグを並列に比較する必要があり、また、LRUの制御も複雑となるなどの問題があるので、VI方式の1次キャッシュの容量はあまり大きくは出来ない。

しかし、別の手として、キャッシュのデータを移して二重に同じ物理番地のデータが格納されないようにする手もある。プロセス1により、ある奇数ページ仮想アドレスのデータがキャッシュの奇数ページ側に格納された状態で、プロセス2が同じ実アドレスのデータを仮想アドレスの偶数ページにマッピングされた状態で読もうとすると、VI方式ではインデックスが異なるので、当然、ミスとなる。そして2次キャッシュにアクセスが行われる。2次キャッシュは通常、PIPT方式であり、そのアクセスのデータが実は1次キャッシュの奇数ページ側にあることがわかる。そうすると、2次キャッシュは1次キャッシュの奇数ページ側のデータを吐き出させ、偶数ページ側に移すという操作を行う。この操作は時間が掛かるので頻繁に移動が行われると性能が低下するが、同一の実ページを一方のプロセスは奇数ページ、他方のプロセスは偶数ページにマッピングして交互にアクセスするケースが稀であれば十分に機能し、最小ページサイズより大きな容量のwayを作ることが出来る。しかし、この方式でもwayあたりの容量はページサイズの2倍とか4倍程度が限界である。

もう一つの手として、実アドレスの偶数ページは仮想アドレスでも偶数ページ、実アドレスの奇数ページは仮想アドレスでも奇数ページにマッピングするようOSのメモリ管理に手を入れるという方法がある。これはハードウェアとしては何もしないで良いが、OSを自分で作っているとか、あるいはOSメーカーに要求を出して変更をしてもらえるということが前提となる。また、wayあたりの容量の単位の大きなページサイズでメモリを管理するのとほぼ等価となり、メモリ割り当ての点では効率が低下する。