是CPU执行的记忆障碍指令,或者只是标记



我试图确切地了解什么是内存屏障。根据我到目前为止所知道的,使用内存屏障(例如:mfence)来防止记忆屏障之前和之后重新订购指令。

这是使用内存屏障的示例:

instruction 1
instruction 2
instruction 3
mfence
instruction 4
instruction 5
instruction 6

现在我的问题是:mfence指令只是一个标记,告诉CPU以什么顺序执行指令?还是CPU实际上执行其他指令(例如:mov)。

每个字节序列在其中遇到的每个字节序列代码是CPU执行的指令。没有其他说明。

您可以在Intel指令集参考和Mfence的特定页面中清楚地看到这一点。

mfence
在所有负载中执行序列化操作 和商店到记忆说明之前发布的说明 Mfence指令。这种序列化操作确保了之前的每个负载和存储指令 在以下任何负载或商店指令之前,程序顺序中的MFENCE指令在全球范围内可见 Mfence指令。

关于所有负载和存储指令,Mfence指令是订购的 Mfence指令,任何LFENCE和SFENCE指令以及任何序列化说明(例如CPUID 操作说明)。Mfence不会序列化指令流。 较弱的记忆类型可用于通过这样的技术来实现更高的处理器性能 排序外的问题,投机性读物,写入综合, 和写入。消费者的程度 数据识别或知道数据在应用程序之间的较弱有所不同,并且可能未知 此数据的生产者。Mfence指令提供 确保负载和存储的性能高效方法 在产生弱排序的例程之间排序 ED消耗数据的结果和例程。

处理器可以免费获取和缓存数据 来自使用WB,WC和的系统内存区域 WT内存类型。这种投机性提取可以随时发生,并且与指令执行无关。因此,它 没有在执行MFence方面订购 操作说明;在执行MFENCE指令之前,之中或之后,可以将数据投机到缓存中。

从摘录中可以看到,MFence指令做了很多工作,而不仅仅是某种标记。

我将解释mfence对管道流的影响。例如,考虑Skylake管道。考虑以下指令序列:

inst1
store1
inst2
load1
inst3
mfence
inst4
store2
load2
inst5

以相同的程序顺序将指令解码为UOPS序列。然后将所有UOPS传递给调度程序。通常,没有围栏,所有UOP都会发行以进行执行。但是,当调度程序接收mfence UOP时,需要确保在mfence下游没有内存UOPS,直到所有上游内存UOPS都在全球可见(这意味着商店已经退休并且负载已完成)。无论访问该区域的内存类型,这都适用于所有内存访问。这可以通过分别使调度程序不发行任何下游商店或加载UOPS或加载UOPS来实现这一点,直到缓冲区排干或发行下游商店或加载UOPS并标记它们,以便它们可以与众不同。缓冲区中的所有现有内存UOPS。围栏上方或下方的所有非记忆UOPS仍然可以置于排序之外。在示例中,一旦store1退休,load1完成(通过接收数据并将其保存在某些内部寄存器中),则mfence指令被认为已完成执行。我认为mfence可能会或可能不会占据后端中的任何资源(ROB或RS),并且可能会被翻译成多个UOP。

Intel在1999年提交了一项专利,该专利描述了mfence的工作原理。由于这是一项非常古老的专利,因此实施可能已经改变,或者在不同的处理器中可能有所不同。我在这里总结专利。mfence被解码为三个UOPS。不幸的是,目前尚不清楚这些UOP的用途。然后将条目从预订站分配,分配给UOPS,并从负载和存储缓冲区分配。这意味着负载缓冲区可以保留用于真实的负载请求或围栏的条目(基本上是虚假负载请求)。同样,商店缓冲区可以保存用于True Store请求和围栏的条目。直到所有较早的负载或存储UOP(在相应的缓冲区中)已退休后,mfence UOP才被派发。发生这种情况时,mfence UOP本身将作为内存请求发送到L1缓存控制器。控制器检查是否已完成所有以前的请求。在这种情况下,它将仅将其视为NOP,并且UOP将从缓冲区中划分。否则,缓存控制器拒绝mfence UOP。

mfence 是指令。

在Linux上获取它:

1/编写文件mfence.c

#include <stdio.h>
int main(){
    printf("Disass men");
    asm volatile ("mfence" ::: "memory");
    return 0;
}

2/compile

gcc mfence.c mfence

3/拆卸

objdump -d mfence | grep -A 10 "<main>:"

000000000000063a <main>:
 63a:   55                      push   %rbp
 63b:   48 89 e5                mov    %rsp,%rbp
 63e:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          callq  510 <puts@plt>
 64a:   0f ae f0                mfence 
 64d:   b8 00 00 00 00          mov    $0x0,%eax
 652:   5d                      pop    %rbp
 653:   c3                      retq   
 654:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 65b:   00 00 00 

4/观察到第64A行mfence是(3位)指令(0f ae f0)

这是CPU指令(例如mov):处理器需要在获得先前的说明之前对其进行解码。

例如,0f ae f0可以出现在地址中,因此CPU不能将其用作制造商。

最后,这只是一条旧学校的指示,在管道中的执行点,它将在执行下一条指令之前同步管道中的内存访问。


注意:在Windows上,使用Macro _ReadWriteBarrier产生Mfence

您的问题的假设错误。Mfence不会阻止重新排序指令(请参阅突出显示的报价)。例如,如果有1000个指令流仅在寄存器上操作,并且中间放置了Mfence指令,则它将对CPU如何重新递延这些说明没有影响。

根据所有负载和存储指令,其他MFENCE指令,任何LFENCE和SFENCE指令以及任何序列化说明(例如CPUID指令),订购了Mfence指令。 MFENCE不会序列化指令流。

相反,MFENCE指令阻止了将加载和存储的重新排序到缓存和主内存。

相关内容

最新更新