キャッシュメモリ


コンピュータで命令を処理するCPUは非常に高速で動作するが、処理を行うプログラムやデータを記憶している主記憶の多くはアクセス速度の遅いDRAMなので、メモリへのアクセスはCPUの動作から考えるととても遅く、普通にメモリアクセスを行うとメモリアクセスがボトルネックをなり処理速度が出ない。
そのため、主記憶とCPUの間に高価ではあるがアクセス速度の速いSRAMなどを配置し、頻繁に使用するデータやプログラムを一時的に記憶し、仮想的に主記憶へのアクセスを高速に見せる技術がキャッシュメモリ(cache memory)である。

具体的にはコンピュータの主記憶(メインメモリ)へのアクセスは、CPUの動作の5〜10倍以上の時間がかかる。プログラムを主記憶に格納しているノイマン型コンピュータでは、1命令に付き必ず主記憶へのアクセス(プログラムフェッチ)が発生するので、いくらCPUの動作周波数を上げても、主記憶のアクセス時間でコンピュータの処理速度が決まってしまう。
主記憶も、DDR-SDRAMやDDR2-SDRAM、DDR3-SDRAMとアクセスの高速化が進んでいるが、CPUの動作周波数の高速化の方が進歩が早いため、主記憶のアクセス速度の改善が必要となる。

キャッシュメモリには高速なアクセスが可能なSRAMが使われ、CPUの内部に配置されている。
主記憶のどのデータをキャッシュメモリに格納するかには、ダイレクトマッピング方式、セットアソシアティブ方式、フルアソシアティブ方式などがある。
処理としては、CPUがメモリからデータを読み出しを行うとき、キャッシュメモリに当該のアドレスのデータがあるかをチェックし、あればキャッシュメモリからデータを読み込み、ない場合は主記憶から読み込み当該データをキャッシュメモリにも書き込む。このとき、キャッシュメモリにデータがある場合をヒット、ない場合をミスヒットといい、ヒットしている確率をヒット率(0〜1)という。
主記憶からキャッシュメモリへデータをコピーはブロック単位で行われ、このブロックのサイズのことをキャッシュラインサイズという。

メモリへのデータの書き出しは、とりあえずキャッシュメモリだけを書換え、キャッシュメモリの入れ替えが行われるときに主記憶を書き換える方法(ライトバック方式)と、書き出しをキャッシュメモリと主記憶の両方に行う方法(ライトスルー方式)がある。


ライトバック方式(write-back)

ライトバック方式は、書き出しを行う主記憶の領域がキャッシュメモリにある限り、キャッシュメモリの書き換えだけで行うので、高速な書き出しが可能である。
ただし、キャッシュメモリと主記憶の内容に差が発生するため、CPUを介しない主記憶のアクセスを行うDMA(Direct Memory Access)などを行うとデータの内容が正しくないことがあるため、DMAを使うときにはキャッシュメモリのデータを主記憶に書き出す処理を行う必要がある。

ライトスルー方式(write-through)

ライトスルー方式は、書き出し時にキャッシュメモリと主記憶の両方に行うため、データの内容が一致しているので扱いが容易であるが、書き出し時に都度主記憶へのアクセスが発生するため、アクセスの高速化という意味では不利な方法である。

実効メモリアクセス時間

キャッシュメモリがある場合のシステムでのメモリアクセス時間の求め方は以下のようになる。
【条件】
  • 主記憶のアクセス時間:M
  • キャッシュメモリのアクセス時間:C
  • キャッシュヒット率:r
アクセス時間=C×r +M×(1-r )

上の式からわかるように、実効メモリアクセス時間には、主記憶の容量、キャッシュメモリの容量は関係しない。

キャッシュメモリの注意点

キャッシュメモリとDMAの関係については、I/O装置から主記憶へのDMA転送を行うときには、主記憶の転送先がキャッシュメモリにヒットしていると正しい値が得られないので注意が必要です。
また、メモリマップドI/Oの場合、キャッシュメモリの対象とするアドレスエリアの決定には気をつけましょう。
キャッシュメモリのヒット率が下がると、メモリアクセス時間が主記憶のアクセス時間に近くなるので、プログラムを開発する場合、キャッシュメモリの容量については考慮したほうが良い。(特に、キャッシュメモリのサイズが小さいCPUを使用する場合。)
例えば、キャッシュメモリの容量が32KbyteのCPUで、64Kbyteのデータを繰り返し走査する処理を行うとキャッシュヒット率が下がり非常に処理が遅くなる。
 void func(void)
 {
  int a, b, i;
  char data[65536];

  for(i=0; i<65536; i++)
  {
   data[i] = i * 2;
  }

  for(i=0; i<65536; i++)
  {
   a += data[i];
  }

  for(i=1; i<65536; i++)
  {
   b += data[i] + data[i-1];
  }
 }
このプログラムでは、2つ目と3つ目のfor文の処理はキャッシュヒット率が低いため、3つのfor文をまとめると処理速度が向上する。
キャッシュヒット率は通常のソフトウェア開発環境では知ることができず、キャッシュヒット率を上げるため作業はトライ&エラー的な方法になる。
特にプログラム部分のキャッシュヒット率を上げる作業は困難なので、コンパイラの最適化機能のみとする場合も多い。

戻る 一覧へ