Edited at

アクセラレーションブースト?

More than 1 year has passed since last update.


CPUの仕組み

年明けに公開されたCPUのバグについて、アクセラレーションブーストなる珍説で原稿料を稼いでる不届き者がいるので、まず、CPUの中がどのような仕組みになっているのかざっくりと説明してみます。(ざっくりなので、実際の挙動と違うことをお許しください)


ストール

デスクトップやサーバー用のCPUはクロック周波数が数GHzとなっており内部ではナノ秒単位で動いています。正確にはサブナノ秒で、真空中での光の速度が約30万Km/sなので、1クロックで光が10cmしか進みません。それほどの高速で動いてはいますが、実際にはCPUの外にあるメモリなどのアクセスでは数百クロックを要するため、データが届くまで待たされることになります。これをメモリアクセスによるストールと呼びます。

また、内部で命令を実行しているとき、通常は連続したメモリアドレスから命令を読み込み、解読して内部信号に変換します。この場合にはアドレスが連続しているため、先読みすることでメモリアクセスによって生じるストールを相殺することができますが、条件分岐の場合別のメモリアドレスから命令を読み込むため、このままではストールが発生します。また、変数がメモリ上に割り付けられている場合にも、これをアクセスするためにストールが発生します。


投機実行

条件分岐の際に条件をすぐに判定できればいいのですが、通常このような条件文は様々な計算を伴いますので、条件文自体の実行に多少時間がかかります。そこで条件文が成功する場合、失敗する場合をとりあえず両方実行してしまい、条件文の計算が終了したときに、実行している二つのうち条件に合致したほうを採用し、失敗したほうを捨てます。これが投機実行と呼ばれる仕組みです。


論理レジスタと物理レジスタ

ここまでの説明で、「投機実行で条件の両方を同時に実行なんてできるの?内部のレジスタを両方で使うと問題にならない?」という疑問がでてきます。例えばx86系のCPUではAX,BX,CXなどというレジスタがあり、コンパイラがこれらのレジスタを使用するように機械語を生成します。投機実行で同時にこれらのレジスタを使うわけにはいきませんが、8086の時代には内部にこれらのレジスタ群がありましたが、現在のCPUでは内部にはより多くのレジスタが組み込まれており、これらのレジスタにコンパイラが生成したレジスタを動的に割り当てています。Skylakeでは整数を扱うレジスタが180個あり、これを便宜的に物理レジスタ(ファイル)、コンパイラが生成した機械語のレジスタを論理レジスタと呼びましょう。

つまり、投機実行で条件文が成功したとき、失敗したときの両方を別々の物理レジスタに割り付ければ、同じ論理レジスタを使う場合でも実際には別の物理レジスタですので問題なく両方を実行できるというわけです。そのうえで条件文の計算が終了した時点で、条件に合致したほうのレジスタをそのまま使い続け、合致しなかったほうの物理レジスタは解放してしまえばよいというわけです。


分岐予測

ここまでは”理想的”なCPUの仕組みで説明しましたが、条件分岐の両方を共に実行する場合に”現実的”なCPUでは内部のALUなどの数に限りがあり、両方を同時に実行した場合はこれら有限のリソースの奪い合いが発生し、ストールします。もし、条件文の結果がある程度予測できるとしたら、その予測結果をもとに条件分岐の片方だけを実行し、リソースの奪い合いを回避することができます。

ある程度まで予測した条件分岐のほうを実行し、もしこの条件が間違っていた場合には、前に述べたように分岐の時点で論理レジスタを別の物理レジスタにコピーしておき、この内容を使って処理を切り替えればよいというわけです。

この方法では条件分岐の予測がどの程度正確かが問題となります。私はあるとき二世代のCPUについて分岐予測の精度を測定したことがありますが、一世代前のCPUで85%(かなり前のことなので大体このくらいとしか覚えていません)でしたが、その次の世代のCPUではこの値が一気に95%まで向上しており、驚いた覚えがあります。おそらく、現在のCPUではさらに分岐予測の精度は上がっていると考えられます。ここまで予測精度が上がってくると、条件分岐の片方だけを投機実行しても十分な実行速度が出せるのです。


結論

で、アクセラレーションブーストなどというものは、不届き者の妄想の産物なんです。