アトミック操作コスト


93

アトミック操作(コンペアアンドスワップまたはアトミック加算/デクリメントのいずれか)のコストはいくらですか?どのくらいのサイクルを消費しますか?SMPまたはNUMAで他のプロセッサを一時停止しますか、それともメモリアクセスをブロックしますか?アウトオブオーダーCPUのリオーダーバッファをフラッシュしますか?

キャッシュにはどのような影響がありますか?

x86、x86_64、PowerPC、SPARC、Itaniumなどの最新の人気のあるCPUに興味があります。


@ジェイソンS、任意。casとatomicinc / decの違いはごくわずかです。
osgx 2010年

2
x86でのアトミック操作は、メモリアドレスでより多くの競合が発生するため、遅くなります。一般に、ロックされていない操作よりも1桁ほど遅いと思いますが、これは、使用される操作、競合、およびメモリバリアによって明らかに異なります。
Stephen Nutt 2010年

うーん。書き込みはx86ではアトミックなようです。「Linuxカーネルを理解する」->
spin_unlock

32ビット書き込みはJavaではアトミックです。つまり、移植可能にアトミックです(ただし、メモリバリアのセマンティクスがないため、ポインタには不十分なことがよくあります)。LOCKプレフィックスを追加しない限り、1の追加は通常アトミックではありません。Linuxカーネルについては、spin_unlockを調べる必要はありません。現在のリリースでは、arch / x86 / include / asm / atomic_32.h(以前はinclude / asm-i386 / atomic.hでした)を参照してください。
Blaisorblade 2010

@ Blaisorblade、JAvaはここにありません。LOCKED操作のコストはいくらですか?
osgx 2010

回答:


61

過去数日間の実際のデータを探しましたが、何も見つかりませんでした。ただし、アトミック操作のコストとキャッシュミスのコストを比較する調査を行いました。

lock cmpxchgPentiumPro(ドキュメントで説明されている)の前のx86 LOCKプレフィックス(アトミックCASを含む)のコストは、メモリアクセス(キャッシュミスなど)、+他のプロセッサによるメモリ操作の停止、+他のプロセッサとの競合ですバスをロックしようとしています。ただし、PentiumPro以降、通常のライトバックキャッシュ可能メモリ(ハードウェアと直接通信しない限り、アプリが処理するすべてのメモリ)の場合、すべてのメモリ操作をブロックする代わりに、関連するキャッシュラインのみがブロックされます(@osgxの回答のリンクに基づく) 。

つまり、コアは、実際のlocked操作のストア部分が終了するまで、回線に対するMESI共有およびRFO要求への応答を遅らせます。これは「キャッシュロック」と呼ばれ、その1つのキャッシュラインにのみ影響します。他のコアは、他のラインを同時にロード/保存したり、CASしたりすることもできます。


実際、このページで説明されているように、CASのケースはより複雑になる可能性があり、タイミングはありませんが、信頼できるエンジニアによる洞察に満ちた説明があります。(少なくとも、実際のCASの前に純粋なロードを実行する通常のユースケースでは。)

詳細に入る前に、ロックされた操作には1つのキャッシュミス+同じキャッシュライン上の他のプロセッサとの競合の可能性がありますが、CAS +先行するロード(ミューテックスを除いてほとんど常に必要です。 CAS 0および1)は、2つのキャッシュミスが発生する可能性があります。

彼は、単一の場所でのロード+ CASは、Load-Linked / Store-Conditionalのように実際には2つのキャッシュミスが発生する可能性があると説明しています(後者については、そこを参照してください)。彼の説明は、MESIキャッシュコヒーレンスプロトコルの知識に依存しています。キャッシュラインには4つの状態を使用します:M(odified)、E(xclusive)、S(hared)、I(nvalid)(したがって、MESIと呼ばれます)。必要に応じて以下で説明します。説明されているシナリオは次のとおりです。

  • LOADにより、キャッシュミスが発生します。関連するキャッシュラインがメモリから共有状態でロードされます(つまり、他のプロセッサは引き続きそのキャッシュラインをメモリに保持できます。この状態での変更は許可されません)。場所がメモリ内にある場合、このキャッシュミスはスキップされます。考えられるコスト:1キャッシュミス。(キャッシュラインが共有、排他的、または変更された状態にある場合、つまりデータがこのCPUのL1キャッシュにある場合はスキップされます)。
  • プログラムは、保存する新しい値を計算します。
  • アトミックCAS命令を実行します。
    • 同時変更を回避する必要があるため、キャッシュラインを排他状態に移行するには、他のCPUのキャッシュからキャッシュラインのコピーを削除する必要があります。考えられるコスト:1キャッシュミス。すでに排他的に所有されている場合、つまり排他状態または変更状態の場合、これは必要ありません。どちらの状態でも、他のCPUはキャッシュラインを保持していませんが、排他状態では(まだ)変更されていません。
    • この通信の後、変数はCPUのローカルキャッシュで変更され、その時点で他のすべてのCPUにグローバルに表示されます(キャッシュが私たちのキャッシュとコヒーレントであるため)。最終的には、通常のアルゴリズムに従ってメインメモリに書き込まれます。
    • その変数を読み取ったり変更したりしようとしている他のプロセッサは、最初に共有モードまたは排他モードでそのキャッシュラインを取得する必要があります。そうするために、このプロセッサに接続して、キャッシュラインの更新バージョンを受け取ります。代わりに、LOCKされた操作は、キャッシュミスのみを発生させる可能性があります(キャッシュラインは排他状態で直接要求されるため)。

いずれの場合も、キャッシュライン要求は、すでにデータを変更している他のプロセッサによって停止する可能性があります。


なぜ他のCPUの状態を変更すると、1つのキャッシュミスが発生するのですか?
osgx 2010年

1
これは、CPUの外部との通信であるため、キャッシュへのアクセスよりも低速です。キャッシュミスはとにかく他のCPUから渡さなければなりませんが。実際、最新のXeonプロセッサでAMD Hypertransport(非常に昔から)やIntelのIntel QuickPath Interconnectなどの直接相互接続が使用されている場合、別のCPUとの通信がメモリとの通信よりも高速である場合があります。 Nehalemに基づいています。それ以外の場合、他のCPUとの通信は、メモリ用のFSBと同じFSBで行われます。詳細については、ウィキペディアでHyperTransportとフロントサイドバスを検索してください。
Blaisorblade 2010年

うわー、彼がそれほど高価だとは決して思っていませんでした-キャッシュミスは数千サイクルになる可能性があります。
Lothar 2010

2
本当に?私が慣れている数字は、キャッシュミスの場合は100サイクル、コンテキスト/特権スイッチ(システムコールを含む)の場合は数千サイクルです。
Blaisorblade 2011年

1
キャッシュミスは数千サイクルではありません!典型的には300〜350回のCPUサイクルでその約100nsの、....
user997112

37

次の設定でプロファイリングを行いました。テストマシン(AMD Athlon64 x2 3800+)を起動し、ロングモード(割り込みを無効)に切り替え、対象の命令をループで実行し、100回の反復を展開し、1,000回のループサイクルを実行しました。ループ本体は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サイクルでした。ロックBTの場合、時間差は1命令あたり約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

ありがとう!テストコードを公開したり、Core2 / Core i3 / i5 / i7を自分でテストしたりできますか?テストセットアップですべてのコアが初期化されましたか?
osgx 2013

ソースコードを追加しました。1つのコアのみが初期化されました。他のマシンからの結果を見たいです。
ティモ

CLFLUSHは、キャッシュ全体のWBINVDよりもはるかに軽い方法でキャッシュラインをフラッシュする必要があります。 WBINVDは命令キャッシュもフラッシュするため、余分なキャッシュミスが発生します。
Peter Cordes 2016年

共有状態でキャッシュラインがホットになっている場合をテストするのはおそらく興味深いことです。別のスレッドに純粋な負荷でそれを読み取らせることで、それを実現できます。
ピーターコーデス

3

バスベースの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 /ロックされたRMW / read-modify-write =アトミック自体/命令は、プロセッサがロックされた命令の前にすべての命令を実行することを保証します。/約まだフラッシュされていない書き込み/次の命令を実行する前に、プロセッサ内で投稿されたすべての書き込みを外部メモリに強制的にフラッシュします。

/ about SMP /セマフォはS状態のキャッシュにあります...日付の0バイトに対して読み取りおよび無効化トランザクションを発行します(これは隣接するCPUのキャッシュラインの共有コピーの強制終了/です/)


1
バスベースのSMPは、1995年のP6 / Pentium Proアーキテクチャ以降は使用されていません(ソース)。今、LOCKデータがキャッシュラインにずれている場合を除き、バスは毎回ロック作る、またはキャッシュの競合がありません。最新の番号については、rigtorp.se / split - locksを確認してください。
ArnaudBouchez20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.