POWER6のキャッシュコヒーレンシ方式

キャッシュは使用頻度の高いデータを近くに置くことにより、実効的なメモリアクセスレーテンシを短縮する手段であるが、マルチコアのシステムでは、複数のコアのキャッシュに同一のアドレスのメモリのデータが載っている状態が存在する。この状態で、1個のコアが自分のキャッシュの状態だけを書き換えると、同一メモリアドレスのデータとして異なる状態が存在することになり、矛盾が起こる。

このような矛盾を避けるため、マルチコアの全部のキャッシュの状態を矛盾のないように保つことをキャッシュコヒーレンスをとるという。この方法には、大まかにブロードキャスト-スヌープ方式とディレクトリ方式がある。

ブロードキャスト-スヌープ方式では、ロードでキャッシュミスを起こしたコアは、そのロードアドレスをシステム内の全部のコアにブロードキャストする。これを受け取ったコアは、自分のキャッシュにこのアドレスのデータがあるかどうかを調べ(スヌープ)、データがあれば送り返す。

一方、ディレクトリ方式では、キャッシュミスが起こると、そのロードアドレスに対応するメモリをもつコア(ホームノードと呼ぶ)に要求を送る。ホームノードは、そのアドレスのデータがほかのコアのキャッシュに格納されているかどうかを管理するテーブル(ディレクトリ)を持っており、ほかのコアに書き換えられた最新のデータがある場合は、そのコアにキャッシュミスを起こしたコアに最新のデータを送るよう指令を出す。そうすると最新データを持つコアからデータが送られるという手順となっている。

全部のコアの間に直接の通信路がある場合は、ブロードキャスト方式では2ホップで処理が終わるのに対して、ディレクトリ方式では3ホップが必要となり、性能的に不利である。しかし、各コアがキャッシュミスを起こす頻度が一定とすると、ブロードキャスト方式では、システム内のコア数の2乗に比例してブロードキャスト-スヌープの回数が増加するので、大規模なシステムには適用が困難である。一方、ディレクトリ方式はブロードキャストを使わず1対1の通信でキャッシュコヒーレンスを取るので、コア数に対するスケーラビリティーが高いという特徴がある。

今回、IBMはPOWER6のキャッシュコヒーレンシ方式として、ブロードキャストとディレクトリ方式のハイブリッド方式であると発表した。

図2に示すように、最大構成である32チップのシステムは、4チップを単位としたノードを8ノード持ち、それらの間を完全結合した構成となっている。そして、各ノードの4個のチップ間も完全結合という2段階の接続形式になっている。

図2 32個のPOWER6で構成したシステム

ディレクトリ方式では、メモリのデータに対してキャッシュライン単位でそのデータがどのノードにコピーされているか、そしてどのノードが最新の状態を持っているかを管理するディレクトリを持つのが一般的である。一方、POWER6では単純にほかのノードにコピーされているか否かを示す1ビットの情報だけを持つ方式を採用している。そして、この1ビットはECCのチェックビットの中に埋め込まれており、特別にメモリを追加することなく、通常の1バイト(=9ビット)のメモリだけで実現している。

発表資料では詳細な動作が分からず、筆者の推測を含んでいるが、おおよそ以下のように動作すると考えられる。

通常のキャッシュでは、ほかのチップのWrite要求に伴って無効化されたキャッシュラインはInvalidとマークされる。しかしPOWER6では、それがノード内のプロセッサから無効化された場合(In状態)と、他のノードのプロセッサから無効化された(Ig状態)かを区別して記憶する。

あるチップで3次キャッシュミスが起こった場合、そのキャッシュラインがIn状態かIg状態か、あるいはまったくキャッシュに存在しない(Tagがミスヒット)かのどれかの状態となる。ここで、In状態であれば、ノード内のほかのプロセッサがValidキャッシュラインを持っている可能性が高い。したがって、ノード内のチップだけにブロードキャスト-スヌープ(ノードポンプと呼ぶ)を行う。一方、Ig状態であれば、他ノードのチップが持っている可能性が高いので、全ノードにブロードキャスト-スヌープをかける(システムポンプと呼ぶ)。

また、そのキャッシュラインが存在していない場合は、ヒストリに基づく予測機構を用いてノードポンプを行うか、システムポンプを行うかを決定する。

ノードポンプを行った場合でもノード内にはValidキャッシュラインが存在しない場合があるが、その場合は、Ig状態であれば、システムポンプを行う。In状態やキャッシュラインが存在しない場合は、ホームノードに問い合わせを行う。ホームノードはディレクトリビットが`1`の場合は、そのキャッシュラインはほかのノードにコピーされているのでシステムポンプを行い、`0`の場合はホームノードにあるのでデータを要求元に送り返す。

このような方法で全ノードに問い合わせを送るケースを減らし、多コアのSMPシステムにおけるスケーラビリティーの問題を軽減している。