フォンノイマンのボトルネックとCPUキャッシュ
高速CPUはなぜメモリを待つのですか?
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
CPUがいくら速く計算できても、計算する命令とデータが到着しなければ何もできない。 CPUとメモリ間の転送速度が全体の性能を制限する現象をVon Neumann Bottleneck(フォンノイマンボトルネック)と呼ぶ。
CPUはメモリを待つ
フォンノイマン構造では、命令とデータが同じメモリとバスを使用する。
CPUが命令を要求する
↓
メモリから命令を取得する
↓
CPUが必要なデータを要求する
↓
メモリからデータをインポートする
↓
CPUが計算
CPUの計算速度と比較すると、メインメモリへのアクセスは遅い。 さらに、一つの通路で命令とデータが一緒に動くと、お互いの順番を待つ状況も生じる。
キャッシュはこの待ち時間を減らす
現代のCPUは、頻繁に使用する命令とデータをCPUに近いCache Memory(キャッシュメモリ)に事前にインポートします。 L1キャッシュは小さくても非常に高速で、L2とL3に向かって大きくなるのではなく、少しずつ遅くなります。
CPU → L1 Cache → L2 Cache → L3 Cache → Main Memory
速くて小さい遅くて大きい
キャッシュは、プログラムが近いデータを繰り返し使用するというLocality(地域性)を利用する。
- 時間局所性:今使用した値はすぐに再利用される可能性が高い。
- 空間地域性:どのアドレスを使用すればその周辺アドレスも使用する可能性が高い。
配列を前から順番に読み込むコードがあちこち飛び回り、読み取るコードよりキャッシュに有利な理由も空間局所性のためだ。
//連続したメモリを順番に読み出すので、キャッシュが活用されやすい。
for (int i = 0; i < count; ++i)
{
sum += values[i];
}
命令キャッシュとデータキャッシュ
現代CPUはメインメモリでは命令とデータを一緒に置き、L1キャッシュではInstruction CacheとData Cacheを分けることもある。 おかげで、次の命令を取得することと現在のデータにアクセスすることをある程度同時に行うことができます。
これが修正されたハーバード構造と呼ばれる理由だ。 ハーバード構造とフォンノイマン構造のメリットを必要な層で混ぜて使用したのだ。
結局、コンピュータの性能はCPUの演算回数だけでは決まらない。 データをどれくらい連続して配置したのか、キャッシュヒット率がどうなのか、CPUがメモリをどれくらい待っているのかなどのように見なければならない。