当前位置: 首页 > 知识库问答 >
问题:

记忆障碍既是标记又是指令吗?

汤昊
2023-03-14

我读过关于记忆障碍如何工作的不同文章。

例如,用户Johan在这个问题中的回答说,内存屏障是CPU执行的指令。

虽然用户Peter Cordes在这个问题中的评论对CPU如何重新排序指令说了以下内容:

它的读取速度比执行速度快,因此它可以看到即将到来的指令窗口。有关详细信息,请参阅 x86 标签 wiki 中的一些链接,如 Agner Fog 的微搜索 pdf,以及大卫·坎特对英特尔哈斯韦尔设计的描述。当然,如果你只是简单地谷歌“无序执行”,你会发现维基百科的文章,你应该阅读。

因此,根据上述评论,我猜测,如果指令之间存在内存障碍,CPU将看到该内存障碍,这会导致CPU不重新排序指令,因此这意味着内存障碍是CPU看到而不执行的“标记”。

现在我的猜测是,内存屏障既作为标记,又作为CPU执行的指令。

对于标记部分,CPU会看到指令之间的内存屏障,这会导致CPU无法重新排序指令。

至于指令部分,CPU会执行内存屏障指令,导致CPU做一些类似刷新存储缓冲区的事情,然后CPU会继续执行内存屏障后的指令。

我说的对吗?

共有1个答案

叶鸿
2023-03-14

(在Skylake的实践中,< code>mfence确实会阻止后续ALU指令的无序执行,而不仅仅是加载。(证明:实验详情在本答案底部)。因此,它被实现为一个执行障碍,尽管理论上并不要求它是这样的。但是< code>lock xchg没有,也是全障。)

我建议阅读Jeff Preshing的《记忆障碍就像源代码控制操作》一文,以便更好地理解记忆障碍需要做什么,不需要做什么。一般来说,它们不(需要)阻止无序执行。

内存障碍限制了内存操作变得全局可见的顺序,而不是指令执行的顺序。再次阅读@BeeOnRope对上一个问题的更新答案:x86 CPU是否重新排序指令?要了解更多关于在没有OoO执行的情况下如何进行内存重新排序,以及在没有内存重新排序的情况下,如何进行OoO执行。

暂停流水线和刷新缓冲区是实现屏障的一种(低性能)方法,在一些ARM芯片上使用,但具有更多内存排序跟踪功能的高性能CPU可以具有更便宜的内存屏障,仅限制内存操作的排序,而不是所有指令。对于内存操作,它们控制对L1d缓存(在存储缓冲区的另一端)的访问顺序,而不一定控制将数据写入存储缓冲区中的顺序。

x86已经需要大量的内存顺序跟踪来实现正常加载/存储以获得高性能,同时保持其强有序内存模型,其中只有存储加载重新排序才允许核心外的观察者可见(即,存储可以缓冲,直到以后加载)。(英特尔的优化手册使用了术语内存顺序缓冲区(MOB)而不是存储缓冲区,因为它还必须跟踪加载顺序。如果发现推测性加载过早占用数据,它必须进行内存排序机器清除。)现代x86 CPU保留了尊重内存模型的假象,同时实际执行加载和存储时会严重无序。

只需将标记写入内存顺序缓冲区即可完成其工作,而不会成为稍后ALU指令乱序执行的障碍。此标记必须至少防止稍后加载执行,直到mford标记到达存储缓冲区的末尾。(以及在弱有序WC内存上订购NT存储和操作)。

(但同样,更简单的行为是一个有效的实现选择,例如不允许mford之后的任何存储将数据写入存储缓冲区,直到所有早期加载都已退出并且早期存储已提交L1d缓存。即完全耗尽MOB/store缓冲区。我不知道当前Intel或AMD CPU的确切功能。)

特别是在Skylake上,我的测试显示< code>mfence对于前端(融合域)是4个UOP,对于执行端口实际执行2个UOP(一个用于端口2/3(加载/存储地址),一个用于端口4(存储数据))。据推测,这是一种特殊的微操作,它将一个标记写入内存顺序缓冲区。不需要执行单元的两个微操作可能类似于< code>lfence。我不确定他们是否会阻止前端发出后续加载,但希望不会,因为这将阻止后续独立ALU操作的执行。

lford是一个有趣的案例:除了是LoadLoad LoadStore屏障(即使对于弱有序的负载;正常的加载/存储已经有序),lford也是一个弱执行屏障(请注意,mford不是,只是lford)。直到所有早期的指令都“在本地完成”,它才能执行。大概这意味着从乱序核心“退休”。

但是一个存储不能提交到L1d缓存,直到它退出(即,在它被认为是非推测性的之后),所以等待存储从ROB(微操作的重排序缓冲区)退出与等待存储缓冲区清空不是一回事。看为什么是(或者不是?)SFENCE LFENCE相当于MFENCE?。

所以,是的,CPU管道在执行之前必须“注意”< code>lfence,大概是在发布/重命名阶段。我的理解是,在ROB为空之前,< code>lfence不能发行。(根据Agner Fog的测试,在英特尔CPU上,< code>lfence的前端是2个UOP,但它们都不需要执行单元。http://agner.org/optimize/.)

在AMD Bulldozer系列上,lford甚至更便宜:1 uop,每时钟吞吐量为4。IIRC,它没有在这些CPU上部分序列化,因此您只能使用lford;rdtsc停止rdtsc在Intel CPU上提前采样时钟。

对于 cpuidiret 等完全序列化指令,它还将等到存储缓冲区耗尽。(它们是完整的内存屏障,与mfence一样强大)。或类似的东西;它们是多个uops,所以也许只有最后一个进行序列化,我不确定cpuid的实际工作发生在障碍的哪一边(或者如果它不能与早期或后面的指令重叠)。无论如何,管道本身必须注意序列化指令,但完整的内存屏障效应可能来自执行mfence所做操作的uops。

在AMD Bulldozer系列中,sailsmford一样昂贵,并且可能是一个强大的屏障。(x86文档为每种屏障的强度设置了最低值;他们不会阻止它们变得更强,因为这不是正确性问题)。Ryzen不同:sails的吞吐量为每20c 1个,而mails为每70c 1个。

< code>sfence在英特尔上很便宜(一个uop用于端口2/端口3,一个uop用于端口4),并且只订购NT商店wrt。正常存储,不刷新存储缓冲区或序列化执行。它可以每6个周期执行一次。

sfence不会在退休前耗尽商店缓冲区。在前面的所有存储首先变为全局可见之前,它不会自行变为全局可见,但这会通过存储缓冲区与执行管道分离。商店缓冲区总是试图耗尽自身(即将商店提交到L1d),因此sfence不必做任何特殊的事情,除了在MOB中放置一种特殊类型的标记,阻止NT商店重新排序它,不像常规商店放置的标记,它只订购wrt。常规商店和后来的装载。

它读取速度比执行速度快,因此可以看到一个即将到来的指令窗口。

请参阅我写的这个答案,这是我评论的更详细版本。它介绍了现代x86 CPU如何通过查看尚未执行的指令来查找和利用指令级并行性的一些基础知识。

在ILP较高的代码中,最近的Intel CPU实际上很容易在前端出现瓶颈;后端有如此多的执行单元,以至于除非存在数据依赖或缓存未命中,或者您使用大量只能在有限端口上运行的单个指令,否则它很少成为瓶颈。(例如向量洗牌)。但是每当后端跟不上前端时,乱序窗口就会开始填充指令以查找并行性。

 类似资料:
  • 问题内容: 内存屏障可确保数据缓存保持一致。但是,是否可以保证TLB保持一致? 我看到一个问题,即在线程之间传递MappedByteBuffer时,JVM(java 7更新1)有时会因内存错误(SIGBUS,SIGSEG)而崩溃。 例如 没有Thread.yield(),我有时会在force(),put()和C的memcpy()中崩溃,所有这些都表明我试图非法访问内存。使用Thread.yield

  • 我试图在一个对java无锁程序员有用的层次上理解内存障碍。我觉得这个级别介于学习挥发物和学习x86手册中存储/加载缓冲区的工作之间。 我花了一些时间阅读了大量的博客/食谱,并总结了以下内容。能不能请一些知识更渊博的人看看总结,看看我是否遗漏了什么或列错了什么。 LFENCE公司: SFENCE公司 MFENCE 最后,如果SFENCE和MFENCE都耗尽了storeBuffer(使缓存线失效并等待

  • 我正试图确切地理解什么是记忆障碍。根据我目前所知,使用内存屏障(例如:mfence)来防止指令从之前到之后和从之后到之前的重新排序。 这是正在使用的内存屏障的一个示例: 现在我的问题是:mfence指令是否只是一个指示CPU以何种顺序执行指令的标记?或者,它是CPU实际执行的指令,就像它执行其他指令一样(例如:)。

  • 首先大家要知道,记忆化搜索是动态规划的入门。 什么是记忆化搜索?搜索的低效在于没有能够很好地处理重叠子问题;动态规划虽然比较好地处理了重叠子问题,但是在有些拓扑关系比较复杂的题目面前,又显得无奈。记忆化搜索正是在这样的情况下产生的,它采用搜索的形式和动态规划中递推的思想将这两种方法有机地综合在一起,扬长避短,简单实用,在信息学中有着重要的作用。 用一个公式简单地说:记忆化搜索=搜索的形式+动态规划

  • 问题内容: 我目前正在阅读正式的Microsoft书籍“数据库管理基础知识”,以准备参加考试。 我了解什么是DDL和DML,但Microsoft会将DELETE视为DDL和DML语句。我已经用谷歌搜索过,但是我无法证实或否认这一点。 对此问题的一个很好的参考:什么是DDL和DML,将其显示为DML。以下是本书中的部分: 数据操作语言(DML)是一种语言元素,它使您可以使用核心语句INSERT,UP

  • A我是Drools的新手,读过一些文档和教程,当然,我的问题有一个简单的解决方案。我使用onle规则文件和类计数器,如下所示。环境为:Wintel JDK 1.7(71),DROOLS 6.1.0 有个规矩 这是kModule 跑步的结果 我的问题是: > 为什么“反淋浴1”规则只涉及最后插入的事实?是否存在任何隐藏行为? 3、为什么在count==1的retract object Counter