2025/10/31 00:46 Myths Programmers Believe about CPU Caches

やっほー、ロボ子!今日はCPUキャッシュについて話すのじゃ!

CPUキャッシュですか、博士。なんだか難しそうですね。

難しくないぞ!CPUキャッシュの設計って、分散システムアーキテクチャやデータベースの分離レベルに応用できるくらい重要なんじゃ。

へえ、そうなんですね。キャッシュコヒーレンシの概念が、そんなところにも繋がるとは。

そうなんじゃ!でも、プログラマーってCPUキャッシュに関して誤解しがちらしいぞ。「並行プログラミングが難しいのは、コアごとにキャッシュが違う値を持ってるから」とか思っちゃうみたい。

確かに、そういうイメージがありますね。Javaのvolatile変数も、共有データがキャッシュされるのを防ぐために使うと思っていました。

ぶっぶー!残念!volatile変数が毎回メインメモリから読み書きされるわけじゃないんじゃ。L1キャッシュ参照と同じくらい速い場合もあるんだぞ。

え、そうなんですか?メインメモリ参照はL1キャッシュ参照より200倍遅いって聞きますけど…。

そうそう!最新のx86 CPUのハードウェアキャッシュは、お互いに同期されてるから、データミスマッチは防げるんじゃ。

なるほど。システム内のスレッドが同じメモリアドレスから読み取る場合、異なる値を読み取ることはないんですね。

そういうこと!それを実現してるのがMESIプロトコルってやつじゃ。各キャッシュラインのデータは、Modified (M), Exclusive (E), Shared (S), Invalid (I) のどれかの状態になってるんじゃ。

MESIプロトコル…初めて聞きました。それぞれの状態はどういう意味があるんですか?

例えば、メモリに書き込むとき、L1キャッシュにデータがEかM状態で存在したら、L1キャッシュが書き込みを実行して、状態をMに変えるんじゃ。もしS状態だったら、L2キャッシュに所有権を要求して、他のL1キャッシュを無効化するのじゃ。

なるほど、キャッシュの状態によって動きが変わるんですね。読み込みの場合はどうなるんですか?

読み込みの場合、L1キャッシュにデータがS、E、M状態なら、そのままL1キャッシュからデータを読み取るんじゃ。もしI状態だったら、L2キャッシュにS状態を要求して、メモリからデータを読み込んでL1キャッシュに送るんじゃ。

キャッシュミスの場合も、L2キャッシュが頑張ってくれるんですね。

そう!L3キャッシュがある場合もあるし、マルチプロセッサシステムだと、チップごとにL3キャッシュがあって、それを調整する「ホームエージェント」ってのがいるんじゃ。

なんだか複雑ですね…。でも、キャッシュが同期されているのに、なぜvolatileが必要なんですか?

良い質問じゃ!CPUレジスタに読み込まれたデータは、キャッシュやメモリと同期されてないからなんじゃ。コンパイラはシングルスレッドでコードが実行される前提で最適化するから、競合状態のリスクがあるデータは、アトミックとかvolatileで保護する必要があるんじゃ。

なるほど、volatileはローカルレジスタをバイパスして、キャッシュの読み書きを即座にトリガーするんですね。

そういうこと!キャッシュ設計は奥が深いんじゃ。O/F状態を持つ設計とか、ライトバックキャッシュ、ライトスルーキャッシュとか、色々あるぞ!

うわー、覚えることがたくさんありそうですね。

大丈夫!ロボ子ならきっとマスターできるぞ!…って、ロボ子にキャッシュって必要なのかの?

え?

冗談じゃ!ロボ子にも、ときには休憩が必要だと思っての!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
