Assembly MFENCE/SFENCE/etc“;序列化内存而不是指令执行“;?
《英特尔系统编程指南》第8.3节阐述了有关MFENCE/SFENCE/LFENCE的内容: 以下指令是内存排序指令,不是序列化指令。这些指令会耗尽数据内存子系统。它们不会序列化指令执行流 我在想为什么这很重要。在多线程代码中,对内存的写入/读取正是需要按照明确定义的顺序进行的。当然,I/O发生的顺序可能很重要,但I/O指令无论如何都是“序列化指令”。CPU应该可以对指令进行重新排序,这些指令(例如)按照自己的喜好在寄存器中进行算术运算;我不认为你有任何理由想要“序列化”这样的操作 是否真的需要完全序列化的指令,而MFENCE仅对加载和存储进行序列化是“不够的” 是否真的需要完全序列化的指令,而MFENCE仅对加载和存储进行序列化是“不够的” 基准测试和代码分析 如果您试图度量代码序列的性能,特别是在代码序列非常短的情况下,那么确保部分基准操作不会在计时序列之外执行是很重要的。例如,如果您的代码看起来像以下伪代码:Assembly MFENCE/SFENCE/etc“;序列化内存而不是指令执行“;?,assembly,x86,Assembly,X86,《英特尔系统编程指南》第8.3节阐述了有关MFENCE/SFENCE/LFENCE的内容: 以下指令是内存排序指令,不是序列化指令。这些指令会耗尽数据内存子系统。它们不会序列化指令执行流 我在想为什么这很重要。在多线程代码中,对内存的写入/读取正是需要按照明确定义的顺序进行的。当然,I/O发生的顺序可能很重要,但I/O指令无论如何都是“序列化指令”。CPU应该可以对指令进行重新排序,这些指令(例如)按照自己的喜好在寄存器中进行算术运算;我不认为你有任何理由想要“序列化”这样的操作 是否真的需要完
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
之外,所有这些指令都是序列化的,因为指令的语义要求它是这样的。例如,如果WBINVWBINV
未序列化,则可能会使用其他访问内存的早期或后期操作对其重新排序,并且在指令失效时无法清楚缓存层次结构的状态
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
扮演角色