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

内存屏障是CPU执行的指令,还是只是一个标记?

酆乐湛
2023-03-14

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

这是正在使用的内存屏障的一个示例:

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

现在我的问题是:mfence指令是否只是一个指示CPU以何种顺序执行指令的标记?或者,它是CPU实际执行的指令,就像它执行其他指令一样(例如:mov)。

共有3个答案

戈安翔
2023-03-14

Mfard是一个指令。

把它放在Linux:

1/写入文件mfence。c

#include <stdio.h>

int main(){
    printf("Disass me\n");
    asm volatile ("mfence" ::: "memory");
    return 0;
}

2/编译

gcc mfence。c mfence

3/拆卸

<代码>objdump-d mfence | grep-A 10“

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行mford是(3位)指令(0f ae f0)

所以这是一个cpu指令(如mov):处理器需要在获取之前解码之前的指令,否则它无法猜测它的对齐。

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

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

注意:在Windows上,使用中的宏ReadWriteBarrier生成mfence

令狐凌
2023-03-14

我将解释mfence对管道流的影响。以Skylake管道为例。考虑以下说明顺序:

inst1
store1
inst2
load1
inst3
mfence
inst4
store2
load2
inst5

指令以相同的程序顺序被解码为一系列uops。然后所有uops都按顺序传递给调度程序。通常,如果没有Geofence,所有uops都会被发出以无序执行。但是,当调度程序接收到m栏uop时,它需要确保在所有上游内存uops变得全局可见之前,m栏下游没有内存uops被执行(这意味着存储已经退出并且加载至少已经完成)。这适用于所有内存访问,而不管正在访问的区域的内存类型如何。这可以通过让调度器分别不向存储或加载缓冲区发出任何下游存储或加载uops来实现,直到缓冲区耗尽,或者通过发出下游存储或加载uops并标记它们,以便它们可以与缓冲区中所有现有的内存uops区分开来。Geofence上方或下方的所有非内存uops仍然可以无序执行。在示例中,一旦store 1退出并且load1完成(通过接收数据并将其保存在某个内部寄存器中),mford指令被认为已完成执行。我认为mford可能会也可能不会占用后端(ROB或RS)中的任何资源,并且它可能会被翻译成多个uop。

Intel在1999年提交了一项专利,描述了mford的工作原理。由于这是一项非常古老的专利,因此实现可能已经改变,或者在不同的处理器中可能会有所不同。我将在这里总结专利。mford被解码为三个uops。不幸的是,尚不清楚这些uops的确切用途。然后从预留站分配条目以保存uops,并从加载和存储缓冲区分配条目。这意味着加载缓冲区可以保存真实加载请求或栅栏(基本上是虚假加载请求)的条目。类似地,存储缓冲区可以保存真实存储请求和栅栏的条目。直到所有较早的加载或存储uops(在各自的缓冲区中)都已停用,mfoxuop才会被调度。当这种情况发生时,mforduop本身会作为内存请求发送到L1缓存控制器。控制器检查是否所有先前的请求都已完成。在这种情况下,它将被简单地视为NOP,并且uop将从缓冲区中被dealldale。否则,缓存控制器会拒绝mforduop。

马欣德
2023-03-14

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

您可以在“英特尔指令集参考”和mfence的特定页面中清楚地看到这一点。

MFENCE
对在MFENCE指令之前发出的所有从内存加载和从存储到内存的指令执行序列化操作。此序列化操作保证在MFENCE指令之后的任何加载或存储指令之前,以程序顺序在MFENCE指令之前的每个加载和存储指令都变得全局可见。

MFENCE指令相对于所有加载和存储指令、其他MFENCE指令、任何LFENCE和SFENCE指令以及任何序列化指令(例如CPUID指令)进行排序。MFENCE不会序列化指令流。弱有序内存类型可用于通过无序问题、推测读取、写入组合和写入折叠等技术来实现更高的处理器性能。数据消费者识别或知道数据弱有序的程度因应用程序而异,并且该数据的生产者可能不知道。MFENCE指令提供了一种性能高效的方式来确保在产生弱有序结果的例程和消耗该数据的例程之间进行加载和存储排序。

处理器可以自由地从使用WB、WC和WT内存类型的系统内存区域推测性地获取和缓存数据。这种推测性抓取可以随时发生,并且与指令执行无关。因此,它不是针对MFENCE指令的执行而排序的;可以在执行MFENCE指令之前、期间或之后推测性地将数据带入缓存。

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

 类似资料:
  • 我发现x86 CPU具有以下内存屏障指令:

  • 我读过关于记忆障碍如何工作的不同文章。 例如,用户Johan在这个问题中的回答说,内存屏障是CPU执行的指令。 虽然用户Peter Cordes在这个问题中的评论对CPU如何重新排序指令说了以下内容: 它的读取速度比执行速度快,因此它可以看到即将到来的指令窗口。有关详细信息,请参阅 x86 标签 wiki 中的一些链接,如 Agner Fog 的微搜索 pdf,以及大卫·坎特对英特尔哈斯韦尔设计的

  • 问题内容: 我有一个包含单元测试的Go文件,其中一些使用了公共变量。我正在测试的代码中使用了另一个全局变量。所有这些都可能导致问题。 在Go中,当我们执行位于同一文件中的测试时,它们如何运行?并行还是下一个不会在前一个完成之前开始? 问题答案: 测试起来真的很容易: 使用运行它,输出显示它是顺序的: 因此,正常的测试是依次执行的,但是请不要忘记未定义顺序:如何依次运行golang测试? 还要注意,

  • 我想知道为什么需要内存障碍,我读了一些关于这个Topic的文章 有人说这是因为cpu无序执行,而其他人说这是因为缓存一致性问题导致缓冲区存储和队列失效<那么,需要记忆障碍的真正原因是什么?cpu无序执行或缓存一致性问题?或者两者都有?cpu无序执行是否与缓存一致性有关?x86和arm之间有什么区别?

  • 我试图让这个游戏工作,但它只是显示一个黑屏。这是一个简单的游戏,你只要避免掉块。我看过相关的问题,但没有一个答案对我有用。它说我必须添加更多细节,所以希望这一行足够了,因为idk在这一行还需要写些什么来为我的文章添加细节。我的代码:

  • 问题内容: 我最近在一次演讲中听说,对volatile的写操作会为线程已写入的每个变量触发内存屏障。真的对吗?从JLS看来,似乎只有相关的变量被清除了,而其他变量则没有。有人知道什么是正确的吗?能否给我指出JLS中的具体位置? 问题答案: 对挥发性变量和其他变量的引用是正确的。我没有意识到,before- before的可传递性是VM必须实现的,而不是从定义中得出的。我仍然感到困惑,为什么并没有明