Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

latency・bandwidth・cache line

メモリアクセスには、主に2つの見方があります。

  • latency: 1回の読み書きが始まってからデータが届くまでの待ち時間。
  • bandwidth: 一定時間にどれだけ多くのデータを運べるか。

小さいデータを少しだけ読む場合は latency が効きやすく、 大きな配列を連続して読む場合は bandwidth が効きやすくなります。

cache

CPUはメモリよりはるかに高速に演算できます。 その差を埋めるために、CPUの近くには cache と呼ばれる小さく高速な記憶領域があります。 よく使うデータや、近くのデータをcacheに置くことで、 CPUがメモリを待つ時間を減らします。

重要なのは、CPUがメモリから1個の f64 だけを読むとは限らないことです。 多くの計算機では、メモリは cache line と呼ばれるまとまった単位でcacheへ運ばれます。 典型的なcache lineは64バイト程度です。

f64 は8バイトなので、64バイトのcache lineには f64 が8個入ります。 つまり、a[i] を読んだとき、近くの a[i + 1], a[i + 2] も 同じcache lineに入っている可能性があります。

連続アクセスが有利な理由

配列を先頭から順に読む場合、次に必要なデータが同じcache lineか、 次のcache lineにある可能性が高くなります。 このようなアクセスは計算機にとって予測しやすく、効率的です。

一方、遠く離れた要素を飛び飛びに読む場合、cache lineで運ばれたデータの多くを 使わないまま捨てることになります。

連続アクセス:
  a[0], a[1], a[2], a[3], ...

飛び飛びアクセス:
  a[0], a[1024], a[2048], ...

数値計算では、同じ数式でも配列の並びとloop orderによって速度が変わります。 これは、数学的な演算回数だけでなく、メモリからデータをどう運ぶかが効くためです。

compute bound と memory bandwidth bound

実行時間の主な制約が浮動小数点演算である場合、その計算は compute bound です。 一方、主な制約がメモリからデータを運ぶ速度である場合、 その計算は memory bandwidth bound です。

大きな配列に対して単純な演算を1回ずつ行う処理は、memory bandwidth bound になりがちです。 同じデータをcache上で何度も再利用できる処理は、compute bound に近づくことがあります。

Last change: , commit: 23d4376