2023/08/04

実装した最終的なRingBuffer

徐々に高度になるリングバッファの話 - Software Transactional Memoを読んで実装した。
リングバッファの書き込みの位置と参照の位置の共有のインデクスの読み書きをマルチプロセスでおこなう場合、メモリの読み込み速度に影響が出る。
CPUキャッシュにはキャッシュラインの単位(キャッシュの情報を調べる方法 - teastat)でキャッシュします。
キャッシュラインごとにステートをもっており、書き換えが発生したキャッシュラインを別のプロセスから参照するとCPUのコアに問い合わせてステートを変更する必要がある。
変数を触る人が限られているため、参照だけする側はキャッシュしたインデクスだけを参照することで、キャッシュのもととなる実物を参照する回数を減らすことでキャッシュヒット率をあげる。

ただし、キャッシュと実物が同じキャッシュラインにのらないように調節する必要がある。(同じキャッシュラインだと書き込みが発生したときステートが変わってコアへの問い合わせが発生する。)
GoでやるならCPUキャッシュがGoのコードに与える影響(翻訳)|TechRacho by BPS株式会社で書かれているように構造体にキャッシュラインと同じだけパディングを用意する。
倍くらい早くなっている。

shoma🥲[main]~/dev/ringbuffer ./mpmc2
finished benchmark. 2097152 times, elapsed 86.395465 ms, 24273.866690 op/ms
shoma🥲[main]~/dev/ringbuffer ./mpmc3
finished benchmark. 2097152 times, elapsed 44.432209 ms, 47198.913743 op/ms

CPUキャッシュのことを考えずに通常の実装をした場合の命令の数とキャッシュミスの数。

==9746== I   refs:      481,381,624
==9746== I1  misses:          3,356
==9746== LLi misses:          2,115
==9746== I1  miss rate:        0.00%
==9746== LLi miss rate:        0.00%

構造体にパディングを加えてキャッシュラインを意識した実装にした場合、2倍以上の命令数(I refs)に対して同じ程度のキャッシュミスの数のため、キャッシュヒット率が大きく増加している。

==10154== I   refs:      1,153,382,268
==10154== I1  misses:            3,412
==10154== LLi misses:            2,116
==10154== I1  miss rate:          0.00%
==10154== LLi miss rate:          0.00%

読んだ記事