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

x86 CPU有多少个内存屏障指令?

孟昊空
2023-03-14

我发现x86 CPU具有以下内存屏障指令:mfence、lfence和sfence。

x86 CPU只有这三个内存屏障指令,还是还有更多?


共有2个答案

方飞鸣
2023-03-14

你说得对,x86 CPU上只有三个内存屏障功能:

LFENCE

SFENCE

MFENCE
段干玺
2023-03-14

sfence(SSE1)和mfence(SSE2)是唯一以其内存Geofence/屏障功能命名的指令。除非使用NT加载或存储和/或WC内存,否则内存排序只需要mfence。

(请注意,Intel CPU上的lfence也是无序执行的障碍,因此它可以序列化rdtsc,并有助于频谱缓解以防止推测性执行。在AMD上,必须设置MSR,否则lfence基本上是nop(4个周期吞吐量)。MSR是通过Spectre缓解微码更新引入的,通常由更新的内核设置。)

锁定指令,如锁定添加[mem],eax也是满内存屏障。锁xchg是否具有与mfence相同的行为?。(虽然从WC内存中排序NT负载可能不如mfence强:锁定的指令是否在弱顺序访问之间提供了障碍?)xchg[mem],reg有一个隐式锁前缀,所以它也是一个障碍。

在我在Skylake上的测试中,lock指令会阻止NT存储与使用此代码的常规存储的重新排序https://godbolt.org/g/7Q9xgz.

xchg似乎是执行seq cst存储的好方法,尤其是在Skylake等Intel硬件上,其中mfence也会阻止纯ALU指令的无序执行,如lfence:请参阅此答案的底部。

AMD还建议使用xchg或其他锁定指令,而不是mfence。(mfence在AMD手册中被记录为在AMD上序列化,因此它总是会受到阻止OoO exec的惩罚)。

对于没有SSE的32位目标上的顺序一致性存储或完全屏障,编译器通常使用lock或[esp]、0或其他无操作锁定指令来实现内存屏障效果。这就是g 7.3-O3-m32-mno-ssestd::atomic_thread_fence(std::memory_order_seq_cst);所做的。

但无论如何,无论mford还是locked insns在架构上都没有被定义为在Intel上序列化,而不管某些CPU上的实现细节如何。

像cpuid这样的完全序列化指令也是完全的内存屏障,会耗尽存储缓冲区并刷新管道。锁xchg是否具有与mfence相同的行为?引用了英特尔手册中的相关内容。

在英特尔处理器上,以下是体系结构序列化指令(来自:https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-273.html):

>

  • 特权序列化指令-INVD、INVEPT、INVLPG、INVVPID、LGDT、LIDT、LLDT、LTR、MOV到控制寄存器、MOV(到调试寄存器)、WBINVD和WRMSR。

    例外:MOV CR8没有序列化。WRMSR到IA32_TSC_DEADLINEMSR(MSR索引6E0H)和X2APIC MSR(MSR索引802H到83FH)没有序列化。

    非特权序列化指令-CPUID、IRET和RSM

    在AMD处理器上,以下是架构上的序列化指令:

    >

  • 特权串行化指令-INVD、INVLPG、LGDT、LIDT、LLDT、LTR、MOV到控制寄存器、MOV(到调试寄存器)、WBINVD、WRMSR和SWAPGS。

    非特权序列化指令-MFENCE、CPUID、IRET和RSM

    英特尔处理器上的术语“[完全]串行化指令”与AMD处理器上的术语含义完全相同,只是有一个区别:AMD处理器上的MFENCE仅针对后续指令订购来自CLFLUSH(但不是CLFLUSHOPT)的缓存线刷新操作。

    in/out(以及它们的字符串复制版本insout)是完整的内存障碍,并且还部分序列化(如lford)。文档说他们会将下一条指令的执行延迟到I/O事务的“数据阶段”之后。

    脚注:

    (1)根据BJ137(Sandy Bridge)、HSD152(Haswell)、BDM103(Broadwell):

    问题:通过从嵌套任务返回导致工作切换的IRET指令不会序列化处理器(与软件开发人员手册第3卷标题为“序列化指令”的部分相反)。

    含义:在任务切换期间依赖IRET的序列化属性的软件可能不会按预期运行。英特尔未遵守此勘误表,以免影响任何商用软件的运行。

    解决方法:未确定。如果需要序列化,软件可以在IRET指令之前立即执行MFENCE指令。

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

    • 问题内容: 最近,我正在阅读一些Linux内核空间代码,我看到了 该代码段的语义是什么?是否确保#1在#3之前由#2执行。但是我有点乱,因为 #A 在64位平台上,atomic64_read宏扩展为 在32位平台中,将其转换为使用锁 cmpxchg8b 。我认为这两个具有相同的语义,对于64位版本,我认为这意味着: all-or-nothing ,我们可以排除地址未对齐且字长大于CPU本机字长的情

    • 问题内容: 我一直在为OpenGL练习编写Minecraft副本(据我估计很多),但是在编写了基本的渲染API之后,我注意到真正的Minecraft 占用了 大量 内存或内存- 大约800MB!我完全可以理解为什么它必须记住所有的块,以及生成器的小怪和地形数据……我问自己:“此块与该块完全相同。它们可以在代码中吗? ” 并记得C ++有指针,所以我试图用我能想到的唯一方法在Java中做同样的事情,

    • 问题内容: 我需要存储大量的日期(可能足够大,以至于需要考虑使用的堆空间量,因此请不要讲授过早的优化),我想知道使用某种原始表示是否有意义java.util.Date(或其他一些现有的Date类)的形式。我知道我可以进行一些性能分析来尝试一下,但是有人知道一个Date对象使用多少字节的内存吗? 问题答案: 我的直觉反应是Date的内存开销非常小。检查源代码,似乎该类仅包含一个实例字段(长为毫秒)。

    • 问题内容: 例如,如果我有一个带有两种情况的枚举,它是否比布尔值占用更多的内存?语言:Java,C ++ 问题答案: 在Java中,an 是成熟的类: Java编程语言的枚举类型比其他语言的枚举类型更强大。枚举声明定义了一个类(称为枚举类型)。枚举类主体可以包括方法和其他字段。 为了查看每个文件的实际大小,让我们做一个实际的文件并检查它创建的文件的内容。 假设我们有以下枚举类: 编译以上内容并反汇

    • 我们目前正在为我们的一个产品添加服务器端脚本功能。作为其中的一部分,我正在评估JSR 223脚本引擎。因为我们可能会在服务器上运行大量的脚本,所以我特别担心这些脚本引擎的内存使用情况。将Rhino(苹果JDK 1.6.0_65-b14-462-11M4609,苹果OS X 10.9.2)与Nashorn(甲骨文JDK 1.8.0-b132)进行比较,每个ScriptEngine实例的内存使用量似乎