MFENCE/LFENCE/SFENCE 函数内部的行为

问题描述

MFENCE/LFENCE/SFENCE 指令作为内部放置在它要序列化的指令之前(A)与必须在需要序列化的指令之前调用的函数内的指令之间的行为有什么区别(乙)?

所以基本上是区别

(A):

LFENCE
RDTSC

(乙):

Fence PROC
LFENCE
RET
Fence ENDP

...

CALL Fence
RDTSC

解决方法

这取决于 Fence 函数中的确切内容。特别是,这取决于围栏和 rdtsc 之间的内容。它还取决于 rdtsc 之后的内容。

考虑 lfence 的情况,其中 rdtsc 位于定时区域的顶部。由于 Fence 是使用 call 指令调用的,因此该函数末尾可能有一个 ret 以返回到后面的 rdtsc。这意味着在 retlfence 之间至少有一个 rdtsc。这里的 ret 很可能是 C3 形式,它被解码并作为现代 Intel 和 AMD 处理器上的两个 uops 分配到保留站。这些 uops 用于从堆栈加载返回地址并验证预测,因此它们之间存在真正的数据依赖性,并且当前处理器不使用值预测。

如果负载在 L1D 和 DTLB 或 STLB 中命中,或者如果值从存储缓冲区转发(这是可能的,因为 lfence 不等待存储缓冲区耗尽),则不太可能在 lfence 之前放置 rdtsc 和在两个指令之间放置 ret 是有区别的。但是如果加载需要很长时间,rdtsc 可能已经被执行,后面的指令也会在后端执行。加载完成后,还有一个来自 ret 的 uop 在 RS 中等待执行。此 uop 会消耗某些资源,并且可能会干扰计时区域内的所有其他 uop,并可能影响测量的时间。请注意,即使使用简单的 Fence 函数,硬件中断也可能发生在 RET 之前,从而无法进行存储转发,最终可能会从 L1D 中驱逐返回地址。无论如何,除非你在定时区域中击中了病理指令序列,否则除非你真的想要极端精确,否则这无关紧要。

您通常希望将 lfence 紧接在 rdtsc 之前。如果可能,您可以使用宏代替函数或强制编译器内联该函数(但即使如此,您仍然必须检查生成的 asm 代码并确保它是您想要的)。

sfence 不与 retrdtsc 交互,因此这些指令没有排序效果。 mfence 强制从 ret 加载,直到大多数较早的内存相关操作达到全局可维护性或持久性点。 mfencesfence 单独不会序列化 rdtsc

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...