SSE3 で monitor / mwait 命令が追加されています。
HT やマルチコアなど、ハードウエアスレッドの同期効率を上げるために有効
らしいですが、使ったことがないので調べてみました。
monitor で監視アドレスを与えた後、mwait 命令は監視アドレスに何らかの
書き込みがあるまで待機します。
メモリの更新をハード的に検出する動作は RISC 系の atomic 命令 ll/sc に
似ています。
イベント待ちのような動作なので様々な通知に使えそうです。ただこれが OS では
なく CPU そのものの命令で実行されるため、いくつかの疑問も生じます。
CPU レベルの命令でアプリケーションがこのような動作を行って問題無いのか、
割り込みやコンテキストスイッチ等でどのように振る舞うのか、
mwait に復帰できるのか、monitor の状態がリストアされるのか、など。
intrin.h を include するだけで、_mm_monitor() / _mm_mwait() の
intrinsic 命令が使えます。
実際に x86 でも x64 でもコンパイルは可能ですが、無効な命令となり実行は
出来ませんでした。
CPUID を調べると、MONITOR/MWAIT に対応していることは確認できます。
・Intel 64 and IA-32 Architectures Software Developer’s Manuals
・日本語技術資料のダウンロード
マニュアルによるとどうやら特権命令らしく、無条件で使えるのはレベル 0
の場合のみ、特権レベル 1~3 での動作も可能だけど、そのためには何らかの
条件がいるそうです。
また MONITOR/WAIT が使えるかどうかは MSR IA32_MISC_ENABLES (1a0) の
bit18 の設定にも依存し、この値が 0 だと CPUID のフラグも落ちるとのこと。
この値も設定されており問題はなさそうです。
Manual の Volume 3A 7.11.3 で、特権レベル 1 以上の場合でこれらの命令が
使えるかどうか判定する方法が載っています。intrinsic で書くと次の通り。
__try{ _mm_monitor( memory, 0, 0 ); } __except( 1 ){ // 使用できない }
つまり Illegal Instruction が発生するのは特権レベル 0 以外は使えないことを
意味しているようです。何らかの設定で無効にされているのか、それとも
もともと使えないものなのか、その条件はわかりませんでした。
マニュアルを見ると mwait の動作は、割り込み等によって頻繁に解除される
ようです。mwait に復帰することはなく、監視したメモリの値を調べて解除原因を
判断する必要があるようです。
また監視メモリの領域は CPU 依存で、CPUID の 0x05 で調べることが出来ます。
手持ちの CPU では下記の通り。最小も最大も 0x40 == 64 でした。
CPUID (CPU-Z によるレジスタダンプ)
・Atom N270
0x00000005 0x00000040 0x00000040 0x00000003 0x00020220
・Core2 Duo E6600
0x00000005 0x00000040 0x00000040 0x00000003 0x00000020
よって何らかの変数を監視するよう割り当てても、同じ 64byte 以内に
割り当てられた他の変数へアクセスによって解除される可能性もあります。
(1) 判定用メモリ領域 64byte (CPUIDで判定) を用意して初期値を入れる
(2) monitor 実行
(3) monitor 命令実行中に書き換えられている可能性があるので判定する。
書き換わっていたら値によって適切な分岐。
(4) 書き換わっていなければ mwait
(5) 解除されたらその要因を調べる。
値が書き換わっていたら値によって分岐。
書き換わっていなければ (2) へ戻る。
もし使うならこのような手順になるようです。
つまりスピンロック時に監視アドレスを与えて停止させられるため、
ループ中に導入することでバスアクセスを減らし、効率を上げることが出来ます。
でも使えませんでした。