2015-09-21 85 views
13

英特尔内存模型保证:Intel内存模型是否使SFENCE和LFENCE冗余?

  • 店将不被重新排序,与其他百货
  • 负载不会重新排序与其它负载

http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

我有由于英特尔存储器模型,但从来没有LFENCE认为SFENCE在x86-64上是冗余的。上述内存模型规则是否使指令冗余?

+0

Err,Store-Load和Load-Store命令如何? –

+0

@IwillnotexistIdonotexist:MFENCE是一个StoreLoad屏障(以及所有其他3种)。是的,你仍然需要它。 :P我不确定movNT加载/存储是否可以显示LoadStore重新排序,或者如果他们省略了单独的LoadStore屏障指令,前提是您在需要LoadStore屏障时通常(总是)需要StoreLoad屏障。因为无论如何它只会影响movnt流操作,这是一个特殊情况的特殊情况,如果没有它,x86很好。 :P –

+0

@PeterCordes [在之前的回答](http://stackoverflow.com/a/22142537/2809095)中,我引用了英特尔SDM的完整列表或允许重新排序。但是我在上面的评论中提到的是,OP大多正确地指出Load-Load和Store-Store重新排序不会发生。然而,这些只是总共四种可能性中的两种(加载存储和存储加载是另外两种组合),并且可能出现其他可能性,因此需要为其提供“防护/防护/防护”功能。 –

回答

12

是的,除了使用movnt(非时间性)流式存储或者将类型设置为非正常回写以外的其他存储区域时,SFENCE和LFENCE不可操作。 NT商店绕过缓存以及弱排序(但是x86's normal memory model is strongly ordered(除了参见下面的Fast-String操作))。 (来自WB存储器的NT加载(movntdqa)为still strongly ordered,因此LFENCE仅在从弱排序存储器读取时有用)。这不会在“正常”程序中偶然发生,所以如果你使用mmap视频RAM或其他东西,你只需要担心这一点。

此帖子:Memory Reordering Caught in the Act是一个易于阅读的同一案例的描述Bartosz的文章谈到,你需要像MFENCE这样的StoreLoad障碍。

如果您在阅读您发布的链接后遇到问题,请阅读Jeff Preshing的博客文章。他们让我对这个问题有了很好的理解。 :)尽管我认为我发现了有关SFENCE/LFENCE通常在Doug Lea的页面中没有任何操作的消息。杰夫的帖子并没有考虑NT装载/商店。


我好奇这几个星期前,并张贴了相当详细的解答到最近的问题: Atomic operations, std::atomic<> and ordering of writes。我包含了很多关于C++内存模型与硬件内存模型的链接。

如果您使用C++编写,使用std::atomic<>是一种很好的方式来告诉编译器您有什么排序要求,所以它不会在编译时重新排序内存操作。您可以并应该使用较弱的版本,或者在适当的情况下获取语义,而不是缺省的顺序一致性,因此编译器在x86上不必发出任何屏障指令。它只需要保持操作源的顺序。


像ARM或PPC,或movnt的x86弱有序的架构,你需要写一个缓冲区,设置标志来表示数据已经准备好之间的StoreStore屏障指令。另外,阅读器在检查标志和读取缓冲区之间需要LoadLoad barrier指令。

不计算movnt,x86已经在每个负载和每个商店之间的StoreStore屏障之间存在LoadLoad屏障。 (LoadStore订购也保证)。 MFENCE是所有4种障碍,包括StoreLoad,这是x86默认情况下不会执行的唯一屏障。 MFENCE确保装载不会在其他线程看到您的商店之前使用旧的预取值,并且可能确实存有自己的商店。 (以及成为NT商店订购和加载顺序的障碍)。

有趣的事实:x86 lock - 前缀指令也是完全内存障碍。它们可以用作旧式32位代码中MFENCE的替代品,可以在不支持它的CPU上运行。lock add [esp], 0否则为空操作,并且在内存上执行读取/修改/写入循环,这在L1高速缓存中很可能很热并且已经处于MESI一致性协议的M状态。

SFENCE是StoreStore的障碍。

LFENCE是LoadLoad和also a LoadStore barrier。 (loadNT/LFENCE/storeNT阻止商店从负载之前成为全局可见,我认为这可能在实践中发生,如果加载地址是一个长期依赖链,或者在高速缓存又一次错过了负载的结果的结果。)


有趣的事实#2(感谢@EOF):Fast-String Ops(IvyBridge和更高版本上的rep stosb/rep movsb)的存储是微弱排序的(但不包括缓存绕过)。

英特尔记录了Fast-String Ops“在其软件开发人员手册”第1卷第7.3.9.3节中出现的“乱序执行”这一事实。他们还表示,

“的任何字符串操作之后,订单相关的代码应该写为离散信号变量 允许正确排序的数据可以看出 所有处理器”

他们不提任何障碍指示。我阅读它的方式是,在rep stosb/rep movsb之后有一个隐含的SFENCE(至少是一个字符串数据的栅栏,可能不是其他飞行中弱有序的NT)。无论如何,措辞意味着写入标志/信号变得全局可见之后的所有字符串移动写入,因此在用快速字符串op填充缓冲区然后写入标志的代码中不需要SFENCE/LFENCE或者在读取它的代码中。 (LoadLoad的排序总是会发生的,所以你总能看到其他CPU使它全局可见的顺序,即使用弱顺序存储来写入缓冲区并不会改变其他线程中的负载仍然强烈排序的事实。)

摘要:使用正常的存储区写一个标志,指示缓冲区已准备就绪。 没有读者只检查用memset/memcpy写入的块的最后一个字节。不过,我认为fast-string商店会阻止任何后来的商店通过它们,所以如果您使用的是movNT,您仍然只需要使用SFENCE/LFENCE。

还有那些可以清除禁用快速串OPS,对于需要运行一个写入“数据准备好”标志为rep stosbrep movsb的一部分老的二进制文件的新服务器,造福CPU MSR位。

+3

这不仅是'movnt',它的内存排序较弱。 memcpy/strcpy-instructions('rep [ne] movs [b/w/d/q]')也可以。 – EOF

+0

@EOF:谢谢,我不知道!奇怪的是,insn参考手册没有提到,只有Vol1手册。我更新了我的答案,并解释了文档的内容:在'rep movsb'后面有一个隐含的StoreStore屏障(对于字符串数据),因此您只需单独编写数据就绪标志(而不是最后一个字节字符串op)。 –

+0

@EOF:它不仅是'movnt'和'rep [ne] movs [b/w/d/q]';但是(可能)每一条访问内存的指令;因为可以通过为被访问的存储器配置PAT /页表或MTRR作为“写入组合”(而不是“写回”)来削弱存储器排序模型。 – Brendan