キャッシュコヒーレンシ

マルチプロセサは、キャッシュが無い場合は共通メモリアクセスのぶつかり合いを解消してやれば良いのであるが、キャッシュを持つようになると、途端に話が面倒になる。

プログラムの命令や定数データなどの書き換えが起こらないデータは複数のプロセサのキャッシュに同じデータがキャッシュされても矛盾は生じない。しかし、図9.3のように、メインメモリの同じアドレスのデータ値がコア0とコア2のキャッシュに入っている状態で、コア0がストアを行い、キャッシュとメインメモリを書き換える(赤の状態)と、コア2のキャシュは古い状態(オレンジ)で残ってしまい、同一アドレスのデータであるのに、異なる値となって矛盾が生じてしまう。

図9.3 マルチプロセサのキャッシュのコヒーレンシ

コア0がある処理を行いその結果をメモリに書き込み、コア2がその結果を使って次の処理を行うというようなケースがあるが、このような協調動作を行う場合は、コア0の処理結果が、自分のキャッシュだけでは無くコア2のキャッシュの内容に反映されなければならないというように、一般に各コアの処理結果も自分のキャッシュだけで無く、他のコアのキャッシュにも正しく反映されなければならない。マルチプロセサの場合、このように複数のプロセサのキャッシュの状態が矛盾しないように制御することが必要であり、これをキャッシュコヒーレンシ(Cache Coherency)を取るという。

マルチプロセサの問題に行く前に、単一プロセサでも必要となるキャッシュラインの状態を復習しておこう。まず、キャッシュラインの状態として、初期化直後で何も入っていない状態や無効化された状態で内容が意味を持たないInvalid状態を示すビットが必要である。そして、キャッシュはInvalid状態のラインに対しては、アドレスがマッチしてもアクセスがヒットしないように制御する。

キャッシュへの書き込みと同時にメインメモリにも書き込みを行うストアスルー(Store Through)方式のキャシュの場合は、このInvalidだけがあれば良いが、ストアはキャッシュに溜め込むライトバック(Write Back)方式のキャッシュの場合は、もう少し、話が複雑になる。ライトバック方式のキャッシュでは、ストアはキャッシュラインにだけに書き込み、メインメモリには書き込まれない。そして、別のアドレスのキャッシュラインのアクセスに伴い、そのキャッシュラインを入れる場所を空けるために、そのラインがキャッシュから追い出される時点でメモリに書き戻しを行う。

ライトバック方式のキャッシュの場合、追い出されるキャッシュラインを常にメインメモリに書き戻してやっても良いのであるが、そのラインへの書き込みが無く、メインメモリから読んだままであれば、再度メモリに同じデータを書き込むのは無駄である。このため、キャッシュラインにはModifiedという属性ビットをつけ、メモリから読み込んだ状態ではリセットし、プロセサからそのラインに書き込みを行うと、そのビットをセットしてModified状態とする。こうしておけば、ラインの追い出し時に、そのラインの属性がModified状態であればメインメモリに書き戻し、Modifiedでなければメインメモリから読まれたままで変更の無いデータであるので、そのまま、ラインのデータを捨ててしまえばよいので、メインメモリへのアクセス回数を減らすことができる。

キャッシュがストアスルー方式で、コモンバス方式のマルチプロセサで一時には1つのプロセサしかメモリにアクセス出来ない構造になっている場合は、図9.4の破線のように、各プロセサがコモンバス上の他のプロセサからの書き込みをモニタして、書き込みデータの取り込み(Write Broadcast)、あるいはそのアドレスを含むキャッシュラインを保持している場合には無効化(Write Invalidate)を行えば、コヒーレンシは保たれる。

図9.4 コモンバスをモニタしてコヒーレンシを確保

しかし、ライトバック方式の場合は、プロセサ0がアドレスAのデータを書き換えても、書き込みが行われるのは自分のキャッシュだけで、コモンバスを使ってメインメモリへの書き込みは行われないので、他のプロセサには書き込みが行われたことが伝達されない。このため、他のプロセサのキャシュには書き換え前のデータが残ってしまいコヒーレンシを保てない。