Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly MFENCE/SFENCE/etc“;序列化内存而不是指令执行“;?_Assembly_X86 - Fatal编程技术网

Assembly MFENCE/SFENCE/etc“;序列化内存而不是指令执行“;?

Assembly MFENCE/SFENCE/etc“;序列化内存而不是指令执行“;?,assembly,x86,Assembly,X86,《英特尔系统编程指南》第8.3节阐述了有关MFENCE/SFENCE/LFENCE的内容: 以下指令是内存排序指令,不是序列化指令。这些指令会耗尽数据内存子系统。它们不会序列化指令执行流 我在想为什么这很重要。在多线程代码中,对内存的写入/读取正是需要按照明确定义的顺序进行的。当然,I/O发生的顺序可能很重要,但I/O指令无论如何都是“序列化指令”。CPU应该可以对指令进行重新排序,这些指令(例如)按照自己的喜好在寄存器中进行算术运算;我不认为你有任何理由想要“序列化”这样的操作 是否真的需要完

《英特尔系统编程指南》第8.3节阐述了有关MFENCE/SFENCE/LFENCE的内容:

以下指令是内存排序指令,不是序列化指令。这些指令会耗尽数据内存子系统。它们不会序列化指令执行流

我在想为什么这很重要。在多线程代码中,对内存的写入/读取正是需要按照明确定义的顺序进行的。当然,I/O发生的顺序可能很重要,但I/O指令无论如何都是“序列化指令”。CPU应该可以对指令进行重新排序,这些指令(例如)按照自己的喜好在寄存器中进行算术运算;我不认为你有任何理由想要“序列化”这样的操作

是否真的需要完全序列化的指令,而MFENCE仅对加载和存储进行序列化是“不够的”

是否真的需要完全序列化的指令,而MFENCE仅对加载和存储进行序列化是“不够的”

基准测试和代码分析

如果您试图度量代码序列的性能,特别是在代码序列非常短的情况下,那么确保部分基准操作不会在计时序列之外执行是很重要的。例如,如果您的代码看起来像以下伪代码:

start = RDTSC()
do some stuff
end = RDTSC()
cycles = end - start
<> P>重要的是要确保中间的代码没有在第一个代码> RDTSC < /C>之前执行,或者在第二个代码之后执行。
令人高兴的是,有一条完美的指令可用于此操作:
CPUID
是完全序列化的。

英特尔手册第8.3节包含被认为是完全序列化的指令的完整列表(另请参见:):

  • 特权串行化指令-INVD、INVEPT、INVLPG、INVVPID、LGDT、LIDT、LLDT、LTR、MOV(用于控制寄存器,带有 MOV CR8 3)、MOV(调试寄存器)、WBINVD和WRMSR的例外情况 四,

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

我认为除了
CPUID
之外,所有这些指令都是序列化的,因为指令的语义要求它是这样的。例如,如果WBINV
WBINV
未序列化,则可能会使用其他访问内存的早期或后期操作对其重新排序,并且在指令失效时无法清楚缓存层次结构的状态

CPUID
指令最初是在奔腾处理器中引入的,奔腾处理器是一种推测性的顺序处理器。此指令的一个典型用途是检查当前处理器是否支持某个特定功能,然后跳转到使用该功能的代码段(如执行指令)。如果
CPUID
没有序列化,我不确定会出现什么复杂情况。例如,如果它用于检查处理器是否支持某些特定指令,并且分支预测器错误地预测了包含该指令的路径,则解码器将其视为无效指令。可以使用用于分支预测失误和无效指令的相同机制来处理这种情况

RDTSC
指令也是在奔腾处理器中首次引入的。但是,奔腾软件开发人员手册中没有提到需要使用带有
RDTSC
的串行化指令。这是有意义的,因为处理器是有序的,2个宽度,因此
RDTSC
只能与它前面或后面的一条指令重叠。在奔腾Pro手册中,它确实提到由于无序执行,您需要使用序列化指令。这里重要的一点是,
CPUID
即使在我们不需要
RDTSC
的处理器上也在序列化。这意味着
CPUID
序列化的最初原因是其他原因。奔腾手册确实提到了两种需要使用序列化指令的情况

15.4。I/O的排序

因此,使用内存映射I/O会导致 I/O读取可能在前一个内存写入之前执行 指示要在Intel486 CPU上消除这种可能性,请使用 读取的I/O指令。为了消除这种可能性 奔腾处理器,插入一条序列化指令,如 CPUID,在操作之间

18.2.3。自修改代码

因为写操作的线性地址是根据线性地址进行检查的 预取说明的地址,请特别注意 当 指令和写入数据的物理地址是 相同,但线性地址不同。在这种情况下,这是必要的 在写入之后和之前执行序列化操作 执行修改后的指令

除了
CPUID
之外的所有序列化指令都不适合用于通用序列化,因为它们要么具有特权,要么会显著影响性能,要么会更改程序流的控制,要么会更改段描述符表
CPUID
也不是完美的,因为它改变了一些体系结构寄存器的值。因此,我认为英特尔有两种选择:要么引入一种新的通用串行化指令,只对管道进行串行化,要么使
CPUID
成为串行化指令。也可能是由于某种原因,
CPUID
本身需要序列化。不管怎样,他们似乎决定让
CPUID
扮演角色