アトミック操作のコストはいくらですか(比較とスワップまたはアトミックな追加/減少のいずれか)?どのくらいのサイクルを消費しますか? SMPまたはNUMA上の他のプロセッサを一時停止しますか、それともメモリアクセスをブロックしますか?異常なCPUのリオーダーバッファをフラッシュしますか?
キャッシュにどのような影響がありますか?
X86、x86_64、PowerPC、SPARC、Itaniumなどの最新の人気のあるCPUに興味があります。
私は過去数日間の実際のデータを探しましたが、何も見つかりませんでした。ただし、アトミック操作のコストとキャッシュミスのコストを比較する調査をいくつか行いました。
PentiumPro(ドキュメントで説明されている)の前のx86 LOCKプレフィックス、またはCASのコストは、メモリアクセス(キャッシュミスなど)、+他のプロセッサによるメモリ操作の停止、+他のプロセッサとのロックの競合バス。ただし、PentiumProの場合、ライトバック(キャッシュ可能な)メモリ(ハードウェアと直接話さない限り、アプリが処理するすべてのメモリ)では、すべてのメモリ操作をブロックするのではなく、関連するキャッシュラインのみがブロックされます(上記のリンクに基づいて)。
実際、CASのケースは このページ で説明されているように、タイミングはありませんが、信頼できるエンジニアによる洞察に満ちた説明が含まれているため、より複雑になる可能性があります。
詳細を説明する前に、ロックされた操作には1つのキャッシュミス+同じキャッシュライン上の他のプロセッサとの競合の可能性がありますが、CAS +前の負荷(mutexを除き、ほとんど常に必要です) CAS 0および1)では、2つのキャッシュミスが発生する可能性があります。
彼は、単一の場所での負荷+ CASには、実際にはLoad-Linked/Store-Conditionalなどの2つのキャッシュミスが発生する可能性があると説明しています(後者については、こちらを参照)。彼の説明は MESIキャッシュコヒーレンスプロトコル の知識に依存しています。キャッシュラインに4つの状態を使用します:M(odified)、E(xclusive)、S(hared)、I(nvalid)(したがって、MESIと呼ばれます)、必要に応じて以下で説明します。説明されているシナリオは次のとおりです。
すべての場合において、すでにデータを変更している他のプロセッサによってキャッシュライン要求が停止する可能性があります。
次のセットアップでプロファイリングを行いました:テストマシン(AMD Athlon64 x2 3800+)が起動され、ロングモードに切り替えられ(割り込みが無効)、目的の命令がループで実行されました。ループ本体は16バイトに揃えられました。時間は、ループの前後にrdtsc命令で測定されました。さらに、命令なしのダミーループが実行され(ループの反復ごとに2サイクルと残りの14サイクルを測定)、結果は命令プロファイリング時間の結果から差し引かれました。
次の指示が測定されました。
lock cmpxchg [rsp - 8], rdx
"(比較一致と不一致の両方)、lock xadd [rsp - 8], rdx
"、lock bts qword ptr [rsp - 8], 1
"すべてのケースで、測定された時間は約310サイクルで、エラーは約+/- 8サイクルでした
これは、同じ(キャッシュされた)メモリ上で繰り返し実行される値です。追加のキャッシュミスがあると、時間がかなり長くなります。また、これはアクティブな2つのコアのうちの1つだけで行われたため、キャッシュは排他的に所有され、キャッシュの同期は必要ありませんでした。
キャッシュミスでロックされた命令のコストを評価するために、ロックされた命令の前にwbinvld
命令を追加し、wbinvld
とadd [rsp - 8], rax
を比較ループに入れます。どちらの場合も、コストは命令ペアあたり約80,000サイクルでした!ロックbtsの場合、時間差は命令ごとに約180サイクルでした。
これは相互スループットであることに注意してください。ただし、ロックされた操作はシリアル化操作であるため、おそらく待ち時間に違いはありません。
結論:ロックされた操作は重いですが、キャッシュミスははるかに重い場合があります。また、ロックされた操作はキャッシュミスを引き起こしません。キャッシュラインが排他的に所有されていない場合にのみ、キャッシュ同期トラフィックが発生します。
マシンを起動するために、ReactOSプロジェクトのx64バージョンのFreeLdrを使用しました。 asmソースコードは次のとおりです。
#define LOOP_COUNT 1000
#define UNROLLED_COUNT 100
PUBLIC ProfileDummy
ProfileDummy:
cli
// Get current TSC value into r8
rdtsc
mov r8, rdx
shl r8, 32
or r8, rax
mov rcx, LOOP_COUNT
jmp looper1
.align 16
looper1:
REPEAT UNROLLED_COUNT
// nothing, or add something to compare against
ENDR
dec rcx
jnz looper1
// Put new TSC minus old TSC into rax
rdtsc
shl rdx, 32
or rax, rdx
sub rax, r8
ret
PUBLIC ProfileFunction
ProfileFunction:
cli
rdtsc
mov r8, rdx
shl r8, 32
or r8, rax
mov rcx, LOOP_COUNT
jmp looper2
.align 16
looper2:
REPEAT UNROLLED_COUNT
// Put here the code you want to profile
// make sure it doesn't mess up non-volatiles or r8
lock bts qword ptr [rsp - 8], 1
ENDR
dec rcx
jnz looper2
rdtsc
shl rdx, 32
or rax, rdx
sub rax, r8
ret
バスベースのSMPでは、アトミックプレフィックスLOCK
はバスワイヤ信号をアサート(オン)しますLOCK#
。それを使用するためにバス上の他のCPU /デバイスを禁止します。
Ppro&P2ブック http://books.google.com/books?id=3gDmyIYvFH4C&pg=PA245&dq=lock+instruction+pentium&lr=&ei=_E61S5ehLI78zQSzrqwI&cd=1#v=onepage&q=lock%20instruction%20pentium&f=false 244-246ページ
ロックされた命令は、シリアル化、同期操作です..../about Out-of-order/locked RMW/read-modify-write = atomic自体/命令プロセッサは、実行前にロックされた命令の前にすべての命令を実行します。 /約まだフラッシュされていない書き込み/次の命令を実行する前に、プロセッサ内のすべてのポストされた書き込みを外部メモリに強制的にフラッシュします。
/ about SMP /セマフォはS状態でキャッシュにあります... 0バイトの日付で読み取りおよび無効化トランザクションを発行します(これは、隣接するCPUのキャッシュラインの共有コピーの削除/です)