メモ: メモリアクセス順序命令 on Intel Core 2
前回、アウトオブオーダの抑制を目的としたcpuid命令の使用を控えましたが、真っ当な手段による抑制方法を知っておきたいと思ったので、調べました。
# まだまだタイマーをいじっています。まずカンタンに解決できそうな課題から。。。
アウトオブオーダとは? 抑制とは?
プロセッサは、最適化のために、コードの記述と異なる順序で命令を実行する場合があります。特に、前後の命令が使用しているレジスタやメモリの値に依存性がない場合に、命令の入れ替えが行われます。
これを抑制するには、CPUに「次に進む前に直前までの命令を実行してね」と教えてあげる命令が必要です。一般的に、メモリバリアといわれる命令です。Intelの用語では、メモリフェンスというようです。
Intelの場合、「直前までの処理」の種類によって、複数の異なる命令が存在します。
手元の環境
- Intel Core 2 CPU 6420 (2.13Ghz)
対処
(今回のタイマーの文脈ならば)カウンタを取得する直前に、MFENCE命令を発行します。
詳細
上記のCPUでは、SFENCE命令、LFENCE命令、MFENCE命令の3つのメモリバリア命令がサポートされています。
Intel CPUの命令アーキテクチャには、加算減算などの基本的な数値演算を含む汎用命令セットの他に、各種の拡張命令セットがあります。その中に、ストリーミングSIMD拡張命令(SSE,Streaming SIMD Extensions)と呼ばれるものがあり、3つのメモリバリア命令はここに含まれています。
各命令の特徴は、語源のとおりです。
- SFENCE(store fence)
- メモリへの書き込み順序を制御します。SFENCEの前に発行された書き込み命令が終わるまで、SFENCEより後の書き込み命令は開始されません。
- LFENCE(load fence)
- メモリの読み込み順序を制御します。LFENCEの前に発行された読み込み命令が終わるまで、SFENCEより後の読み込み命令は開始されません。
- MFENCE(m…?? fence)
- SFENCEとLFENCEの複合版です。MFENCEの間に発行された書き込み/読み込み命令が終わるまで、MFENCEより後の書き込み/読み込み命令は開始されません。
タイマーは次のような処理なので、MFENCEを使えばよいと考えました。
__asm{ sub eax, eax sub edx, edx mfence rdtsc mov start_low, eax mov start_high, edx }
こんなカンジに。
3種類のうち、最初にSFENCE命令が定義されたようで、これだけがSSEに入っています。LFENCE命令とMFENCE命令は、SSEの強化版であるSSE2に含まれます。CPUによっては、SSEをサポートしていてもSSE2はサポートしていない(Pentium3がこれに当たります)ので、マニュアルを確認することが大事です。Core 2 は、SSEとSSE2の両方を取り込んでいます。