torutkのブログ

ソフトウェア・エンジニアのブログ

x86系プロセッサのInvariant TSC

x86系CPUがクロック毎に積算するTSC(Time Stamp Counter)をRDTSC命令で取得して高分解能な時間計測を行う際に、デュアルコアで挙動不審な状況がありました。

また、SpeedStepやTurboBoostなど実行中にCPUクロックが変動するので、TSCが当てにならないという問題もありました。

そのため、しばらくはRDTSCを使った時間計測は信頼性が低いので使えないという判断をしていました。今回、この考えを刷新した方がよいのではと思うようになりました。

最近のプロセッサはInvariant TSCを搭載しており、実行時に変動するクロックやACPIの働きでサスペンドしてもカウンタが一定周期で積算されることが分かりました。

マルチコアの場合、各コアでTSCを持ちそれぞれがカウンタを更新していますが、このInvariant TSCによりコアがそれぞれ異なるクロックで動作したりサスペンド状態になっても常に一定間隔で更新され、また起動時のRESET信号は各コアに同時に届きTSCが0にクリアされるので、異なるコアのTSCを読みだすことになっても問題はない、という見解が成り立つようです。

なお、物理的にソケットが複数ある場合、RESET信号が同時に届くかはシステム(マザーボードの作り)次第なので、1ソケットでのマルチコアマシンでの限定となるかと思います。
といっても、1GHzは1nsですから、電気信号はほぼ高速で伝搬するので30cmとなります。気にするほどの差にはならないのではと思いますが、CPU側では確かに保証できない話です。

その他、アウト・オブ・オーダー実行のプロセッサでRDTSCのタイミングを意図した順序で実行させるため、命令をシリアライズさせるトリックとしてCPUID命令を発行していましたが、最近のプロセッサではRDTSCP命令が追加され、シリアライズをしてくれるようになりました。

また、Windows/Visual C++の新しいバージョン(2005/2008以降)では、インラインアセンブラを使わなくてもRDTSC命令を呼び出すCompiler Intrinsics関数(__rdtsc, __rdtscp)が提供され、簡単にカウンタを取得できるようになっていました。

TSCを使った時間計測について以前書いたWebページに、新しいTSC、RDTSCP、VC++の関数の話などを追記しました。