我已经阅读了有关内存屏障如何工作的不同内容。
例如,用户 Johan 在this question中的答案表示内存屏障是CPU执行的指令。
用户 Peter Cordes 在this question中的评论说明了以下有关CPU如何重新排列说明的信息:
它读取的速度比它可以执行的速度快,所以它可以看到一个窗口 即将到来的指有关详细信息,请参阅x86中的一些链接 标签wiki,像Agner Fog的microarch pdf,以及David Kanter的 英特尔Haswell设计的撰写。当然,如果你只是 谷歌搜索"乱序执行",你找到维基百科的文章, 你应该阅读。
所以我根据上面的评论猜测,如果指令之间存在内存障碍,CPU会看到这个内存屏障,导致CPU不重新排序指令,这意味着内存屏障是一个"标记"让CPU看到而不是执行。
现在我的猜测是内存屏障既可以作为标记,也可以作为CPU执行的指令。
对于标记部分,CPU会看到指令之间的内存屏障,这会导致CPU不对指令重新排序。
对于指令部分,CPU将执行内存屏障指令,这会导致CPU执行诸如刷新存储缓冲区之类的操作,然后CPU将在内存屏障后继续执行指令。
我说错了吗?
答案 0 :(得分:2)
mfence
未在指令流上进行序列化,lfence
(即)不会刷新存储缓冲区。(在Skylake的实践中,mfence
阻止后续ALU指令的无序执行,而不仅仅是加载。(Proof: experiment details at the bottom of this answer)。所以&#39 ; s被实现为执行障碍,即使在纸面上它也不一定是一个。但是lock xchg
并不是,并且也是一个完整的障碍。)
我建议阅读Jeff Preshing的Memory Barriers Are Like Source Control Operations文章,以便更好地了解需要做什么内存障碍,以及他们 >需要做。他们不需要(需要)阻止无序执行。
:一种存储器屏障限制的顺序存储器操作可以成为全局可见的,不的(必须的)的顺序指令执行强>转到读@ BeeOnRope' S更新了对上一个问题的回答:Does an x86 CPU reorder instructions?了解更多关于如何在没有OoO执行的情况下进行内存重新排序的情况,以及如何在没有内存重新排序的情况下发生OoO执行。
停止管道和刷新缓冲区是一种(低性能)方式来实现障碍used on some ARM chips,但是具有更多内存排序跟踪的更高性能CPU可能会有更便宜的内存障碍这只限制了内存操作的顺序,而不是所有指令。对于内存操作,它们控制对L1d缓存(在存储缓冲区的另一端)的访问顺序,而不一定是存储将其数据写入存储缓冲区的顺序。
x86已经需要大量的内存顺序跟踪正常的加载/存储以获得高性能,同时保持其强排序的内存模型,其中只允许StoreLoad reordering对核心外的观察者可见(即存储可以是缓冲,直到后来加载)。 (英特尔的优化手册使用术语“内存顺序缓冲区”或MOB,而不是存储缓冲区,因为它还必须跟踪负载排序。如果事实证明是推测,它必须清除内存订购机器负载过早占用数据。)现代x86 CPU保留了尊重内存模型的错觉,同时实际执行负载并严重无序存储。
mfence
可以通过将标记写入内存顺序缓冲区来完成其工作,而不会成为后续ALU指令的无序执行的障碍< / strong>即可。此标记必须至少阻止以后的加载执行,直到mfence
标记到达存储缓冲区的末尾。 (以及在弱排序的WC内存上订购NT存储和操作)。
(但同样,更简单的行为是一个有效的实现选择,例如,在mfence
向存储缓冲区写入数据之前不允许任何存储,直到所有早期的加载已经退出并且早期的存储已经提交到L1d缓存。完全消耗MOB /存储缓冲区。我不确切知道当前Intel或AMD CPU的用途。)
特别是在Skylake上,my testing shows mfence
前端(融合域)为4 uops,实际执行端口上有2 uop(一个用于port2 / 3(加载/存储 - 地址),一个用于port4(存储数据))。据推测,它是一种特殊的uop,它将标记写入内存顺序缓冲区。不需要执行单元的2个uop可能与lfence
类似。我不确定它们是否会阻止前端甚至发出后续加载,但希望不是因为这会阻止以后独立的ALU操作被执行。
lfence
是一个有趣的案例:除了作为LoadLoad + LoadStore屏障(即使对于弱排序的负载;已经订购了正常的加载/存储), lfence
也是一个弱执行障碍(请注意,mfence
不是lfence
)。它不能执行,直到所有早期指令都在本地完成&#34;。据推测,这意味着&#34;退休&#34;来自无序核心。
但商店不能提交L1d缓存,直到 之后它仍然退休(即在知道它是非推测性的之后),所以等待商店退出ROB(UO的ReOrder Buffer)与等待存储缓冲区清空是一回事。请参阅Why is (or isn't?) SFENCE + LFENCE equivalent to MFENCE?。
所以,是的,CPU管道确实需要注意&#34; lfence
在执行之前,可能是在问题/重命名阶段。我的理解是lfence
无法发布,直到ROB为空。 (根据Agner Fog的测试,在Intel CPU上,前端lfence
为2 uop,但它们都不需要执行单元。http://agner.org/optimize/。
lfence
甚至更便宜:1个uop,每时钟吞吐量为4个。 IIRC,它没有对这些CPU进行部分序列化,因此您只能使用lfence; rdtsc
阻止rdtsc
在Intel CPU上提前对时钟进行采样。
对于完全序列化cpuid
或iret
等指令,它也会等到存储缓冲区耗尽。 (They're full memory barriers, as strong as mfence
)。或类似的东西;他们有多个uop,所以也许只有 last 一个进行序列化,我不确定cpuid
的实际工作发生在屏障的哪一侧(或者如果它不能与之前或之后的指令重叠)。无论如何,管道本身必须注意序列化指令,但完全的内存屏障效应可能来自执行mfence
操作的uops。
在AMD Bulldozer系列中,sfence
与mfence
一样昂贵,并且可能是一个强大的障碍。 (x86文档设定了每种障碍的强度最小值;它们不会阻止它们变强,因为这不是正确性问题)。 Ryzen是不同的:sfence
每20c吞吐量有一个,而mfence
每70c有1个。
sfence
在英特尔上非常便宜(对于port2 / port3是一个uop,对于port4来说是一个uop),并且只是命令NT存储wrt。正常存储,不刷新存储缓冲区或序列化执行。它可以每6个周期执行一次。
sfence
在退休之前不会耗尽商店缓冲区。在所有先前商店首先全局可见之前,它不会全局可见,但这是通过存储缓冲区与执行管道分离的。存储缓冲器总是试图耗尽本身(即承诺店L1D),因此sfence
没有按&#39; t有做什么特别,除了在重新排序的停止NT存储MOB把一种特殊的标志过去它,不像常规商店所提供的商标只能订购。常规商店和以后的货物。
它读取的速度比它可以执行的速度快,所以它可以看到即将发布的指令窗口。
请参阅this answer I wrote,这是我评论的更详细版本。它通过查看尚未执行的指令,介绍了现代x86 CPU如何找到并利用指令级并行性的一些基础知识。
在具有高ILP的代码中,最近的Intel CPU实际上可以很容易地在前端遇到瓶颈;后端有如此多的执行单元,除非存在数据依赖性或缓存未命中,否则它很少成为瓶颈,或者您使用大量只能在有限端口上运行的单个指令。 (例如矢量改组)。但是,只要后端没有跟上前端,乱序窗口就会开始填充查找并行性的指令。