Assembly 内存障碍是CPU执行的指令,还是只是一个标记?
我正试图确切地理解什么是记忆障碍。 根据我目前所知,内存屏障(例如:Assembly 内存障碍是CPU执行的指令,还是只是一个标记?,assembly,x86,cpu-architecture,memory-barriers,memory-fences,Assembly,X86,Cpu Architecture,Memory Barriers,Memory Fences,我正试图确切地理解什么是记忆障碍。 根据我目前所知,内存屏障(例如:mfence)用于防止指令在内存屏障之前到之后和之后到之前重新排序 这是正在使用的内存屏障的一个示例: instruction 1 instruction 2 instruction 3 mfence instruction 4 instruction 5 instruction 6 现在我的问题是:mfence指令只是告诉CPU以什么顺序执行指令的一个标记吗?或者它是CPU实际执行的指令,就像它执行其他指令一样(例如:mov
mfence
)用于防止指令在内存屏障之前到之后和之后到之前重新排序
这是正在使用的内存屏障的一个示例:
instruction 1
instruction 2
instruction 3
mfence
instruction 4
instruction 5
instruction 6
现在我的问题是:
mfence
指令只是告诉CPU以什么顺序执行指令的一个标记吗?或者它是CPU实际执行的指令,就像它执行其他指令一样(例如:mov
)。CPU在其代码中遇到的每个字节序列都是CPU执行的指令。没有其他类型的说明
您可以在和特定页面中清楚地看到这一点
MFENCE对从内存加载的所有数据执行序列化操作 并将之前发出的指令存储到内存 MFENCE指令。这个序列化操作保证前面的每个加载和存储指令 程序顺序中的MFENCE指令在随后的任何加载或存储指令之前全局可见 MFENCE指令 MFENCE指令的顺序与所有加载和存储指令相关,其他 MFENCE指令、任何LFENCE和SFENCE指令以及任何序列化指令(如CPUID 指示)。MFENCE不会序列化指令流。 弱有序内存类型可以通过以下技术实现更高的处理器性能: 出了问题,投机读写结合, 和写折叠。消费者对产品的消费程度 数据可以识别或知道数据的弱顺序在不同的应用程序中有所不同,用户可能不知道 这些数据的生产者。MFENCE指令提供 确保加载和存储的高效性能方法 产生弱顺序的例程之间的顺序 对使用该数据的结果和例程进行编辑 处理器可以随意获取和缓存数据 来自使用WB、WC和 WT内存类型。这种推测性抓取可以在任何时候发生,并且与指令执行无关。因此, 没有命令执行MFENCE 指示在执行MFENCE指令之前、期间或之后,可以推测地将数据带入缓存
从摘录中可以看出,
MFence
指令做了大量工作,而不仅仅是某种标记 我将解释mfence
对管道流的影响。以管道为例。考虑下面的指令序列:
inst1
store1
inst2
load1
inst3
mfence
inst4
store2
load2
inst5
指令以相同的程序顺序被解码成一系列UOP。然后将所有UOP按顺序传递给调度程序。通常情况下,如果没有围栏,所有UOP都会被发布,以便无序执行。但是,当调度程序接收到mfence
uop时,它需要确保mfence
下游没有内存uop被执行,直到所有上游内存uop全局可见(这意味着存储已失效,加载至少已完成)。这适用于所有内存访问,而不考虑所访问区域的内存类型。这可以通过让调度程序在缓冲区耗尽之前不分别向存储区或加载缓冲区发出任何下游存储或加载UOP,或者通过发出下游存储或加载UOP并对其进行标记,以便将其与缓冲区中的所有现有内存UOP区分开来实现。围栏上方或下方的所有非内存UOP仍可以无序执行。在本例中,一旦store1
失效且load1
完成(通过接收数据并将其保存在某个内部寄存器中),则认为mfence
指令已完成执行。我认为mfence
可能会或可能不会占用后端(ROB或RS)中的任何资源,并且可能会转换为多个uop
英特尔在1999年提交了一份报告,描述了
mfence
的工作原理。由于这是一项非常古老的专利,实现可能已经改变,或者在不同的处理器中可能有所不同。我将在这里总结专利mfence
被解码为三个UOP。不幸的是,目前还不清楚这些UOP的确切用途。然后,从预订站分配条目,并将其分配到保存UOP,还从加载和存储缓冲区分配条目。这意味着负载缓冲区可以保存真实负载请求或围栏(基本上是虚假负载请求)的条目。类似地,存储缓冲区可以保存真实存储请求和围栏的条目。在所有先前的加载或存储uop(在各自的缓冲区中)失效之前,mfence
uop不会被调度。当这种情况发生时,mfence
uop本身作为内存请求发送到一级缓存控制器。控制器检查之前的所有请求是否已完成。在这种情况下,它将被简单地视为NOP,uop将从缓冲区中被释放。否则,缓存控制器将拒绝mfence
uop。mfence是一条指令
要在Linux上获得它,请执行以下操作:
1/编写文件mfence.c
#include <stdio.h>
int main(){
printf("Disass me\n");
asm volatile ("mfence" ::: "memory");
return 0;
}
4/注意第64a行的mfence是(3位)指令(0f ae f0)
这是一条cpu指令(如mov
):处理器需要先解码之前的指令,否则无法猜出它的对齐方式
例如,ae f0的0f
可能出现在地址中,因此cpu不能将其用作制造商
最后,这只是一个古老的学校教学,在它的e
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