4

Intel x86/x86_64 システムには、lfence、sfence、mfence の 3 種類のメモリ バリアがあります。それらの使用に関する質問。シーケンシャル セマンティック (SC) は、SC セマンティックMOV [addr], reg + MFENCEを必要とするすべてのメモリ セルに使用するのに十分です。ただし、全体にコードを記述することも、その逆も可能ですMFENCE + MOV reg, [addr]。どうやら、メモリへのストアの数が通常そこからのロードよりも少ない場合、合計で書き込みバリアを使用する方がコストが少ないと感じました。これに基づいて、シーケンシャル ストアをメモリに使用する必要があるため、別の最適化を行いました - [LOCK] XCHG。これは、「XCHG 内の MFENCE」が使用されるメモリのキャッシュ ラインにのみ適用されるため、おそらく安価です。 XCHG ( 0:28:20 で、MFENCE は XCHG よりも高価であると述べたビデオ)。

http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

C/C++11 オペレーション x86 実装

  • Load Seq_Cst: MOV (メモリから)
  • Store Seq Cst: (LOCK) XCHG // 代替: MOV (メモリへ),MFENCE

注: C/C++11 から x86 への代替マッピングがあり、Seq Cst ストアをロック (またはフェンシング) する代わりに、Seq Cst ロードをロック/フェンシングします。

  • Load Seq_Cst: LOCK XADD(0) // 代替: MFENCE,MOV (メモリから)
  • Store Seq Cst: MOV (メモリに)

違いは、ARM と Power のメモリ バリアは LLC (Last Level Cache) のみと対話し、x86 は下位レベルのキャッシュ L1/L2 と対話することです。x86/x86_64 の場合:

  • lfenceCore1: (CoreX-L1) -> (CoreX-L2) -> L3-> (Core1-L2) -> (Core1-L1)
  • sfenceCore1: (Core1-L1) -> (Core1-L2) -> L3-> (CoreX-L2) -> (CoreX-L1)

アームの場合:

  • ldr; dmb;: L3-> (Core1-L2) -> (Core1-L1)
  • dmb; str; dmb;: (Core1-L1) -> (Core1-L2) -> L3

GCC 4.8.2 でコンパイルされた C++11 コード - x86_64 の GDB:

std::atomic<int> a;
int temp = 0;
a.store(temp, std::memory_order_seq_cst);
0x4613e8  <+0x0058>         mov    0x38(%rsp),%eax
0x4613ec  <+0x005c>         mov    %eax,0x20(%rsp)
0x4613f0  <+0x0060>         mfence

しかし、なぜx86/x86_64 Sequential Semantic (SC) で through を使用しMOV [addr], reg + MFENCE、 notを使用するのにMOV [addr], reg + SFENCE、なぜthereMFENCEではなくfull-fence が必要なのSFENCEでしょうか?

4

2 に答える 2

2

sfenceStoreLoad の並べ替えをブロックしません。実行中の NT ストアがない限り、アーキテクチャ上はノーオペレーションです。x86 では StoreStore の並べ替えが許可されていないため、ストアは古いストアがコミットされるのを待ってから、L1d にコミットしてグローバルに表示されます。(NTストア/WCメモリへのストアを除く)

seq_cst の場合、ストア バッファをフラッシュするための完全なバリアが必要です。後でロードする前に、すべての古いストアがグローバルに表示されるようにします。https://preshing.com/20120515/memory-reordering-caught-in-the-act/を 参照してください。実際に使用mfenceに失敗すると、メモリの並べ替えなど、順次一貫性のない動作が発生する例が示されています。


あなたが見つけたように、すべてのseq_cstストア/RMWではなく、すべてのseq_cstロードで完全なバリアを使用してseq_cstをx86 asmにマップすることが可能です。その場合、ストアにバリア命令は必要ありません (したがって、リリース セマンティクスがあります) が、mfenceevery の前に必要になりますatomic::load(seq_cst)

于 2019-03-19T01:25:52.770 に答える
-1

mfence;は必要ありません。sfence確かに十分です。lfence実際、デバイスを扱っていない限り、x86 では必要ありません。mfenceしかし、Intel (および AMD だと思います) は単一の実装をand と共有している (または少なくとも持っていた) sfence(つまり、ストア バッファーをフラッシュする) ため、弱いsfence.

ところで、共有変数に書き込むたびにフラッシュする必要はないことに注意してください。別の共有変数の書き込みとその後の読み取りの間でのみフラッシュする必要があります。

于 2013-11-05T08:41:47.973 に答える