gpt4 book ai didi

assembly - LFENCE 的 x86-64 使用

转载 作者:行者123 更新时间:2023-12-04 14:10:20 24 4
gpt4 key购买 nike

我试图了解在使用 RDTSC/RDTSCP 测量时间时使用围栏的正确方法。关于与此相关的 SO 的几个问题已经得到了详尽的回答。我已经经历了其中的一些。我还浏览了这篇关于同一主题的非常有用的文章:
http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf

但是,在另一个在线博客中,有一个在 x86 上使用 LFENCE 代替 CPUID 的示例。我想知道 LFENCE 如何防止早期商店污染 RDTSC 测量。
例如。

<Instr A>
LFENCE/CPUID
RDTSC
<Code to be benchmarked>
LFENCE/CPUID
RDTSC

在上述情况下,LFENCE 确保所有较早的加载在它之前完成(因为 SDM 说:LFENCE 指令不能通过较早的读取。)。但是早期的商店(比如,Instr A 是一家商店)呢?我理解为什么 CPUID 可以工作,因为它是一个序列化指令,但 LFENCE 不是。

我在 Intel SDM VOL 3A Section 8.3 中找到了一种解释,以下脚注:

LFENCE 确实为指令排序提供了一些保证。直到所有先前的指令都在本地完成后才会执行,并且直到 LFENCE 完成后才开始执行后面的指令。

所以本质上 LFENCE 就像一个 MFENCE。在那种情况下,为什么我们需要两个单独的指令 LFENCE 和 MFENCE?

我可能错过了一些东西。

提前致谢。

最佳答案

关键是副词本地在引用的句子中“直到所有先前的指令都在本地完成后才会执行”。

我无法在整个英特尔手册中找到“本地完成”的明确定义,我的猜测解释如下。

为了在本地完成一条指令,它的输出必须被计算出来并可供其依赖链中更下游的其他指令使用。
此外,该指令的任何副作用都必须在核心内部可见。

为了在全局范围内完成一条指令,它的副作用必须对其他系统组件(如其他 CPU)可见。

如果我们不限定我们谈论的那种“完整性”,通常意味着它不在乎或在上下文中是隐含的。

对于很多在本地和全局完成的指令,都是一样的。
例如,为了在本地完成加载,必须从内存或缓存中获取一些数据。
这与全局完成相同,因为如果我们不先从内存层次结构中读取,我们就无法将加载标记为完成。

然而对于一家商店来说,情况就不同了。

英特尔处理器有一个存储缓冲区来处理对内存的写入,来自手册 3 的第 11.10 章:

Intel 64 and IA-32 processors temporarily store each write (store) to memory in a store buffer. The store buffer improves processor performance by allowing the processor to continue executing instructions without having to wait until a write to memory and/or to a cache is complete. It also allows writes to be delayed for more efficient use of memory-access bus cycles.



因此,可以通过将存储放入存储缓冲区来在本地完成存储,从核心角度来看,写入就像一直到内存一样。
在特定情况下,来自同一存储核心的负载甚至可以读回该值(这称为存储转发)。

然而,要在全局范围内完成,需要从存储缓冲区中排出存储。

最后必须添加存储缓冲区被序列化指令耗尽:

The contents of the store buffer are always drained to memory in the following situations:
• (P6 and more recent processor families only) When a serializing instruction is executed.
• (Pentium III, and more recent processor families only) When using an SFENCE instruction to order stores.
• (Pentium 4 and more recent processor families only) When using an MFENCE instruction to order stores.



介绍完了,我们来看看 lfence , mfencesfence做:

LFENCE does not execute until all prior instructions have completed locally, and no later instruction begins execution until LFENCE completes.

MFENCE performs a serializing operation on all load-from-memory and store-to-memory instructions that were issued prior the MFENCE instruction. MFENCE does not serialize the instruction stream.

SFENCE performs a serializing operation on all store-to-memory instructions that were issued prior the SFENCE instruction.



所以 lfence 较弱的序列化形式不会耗尽存储缓冲区 ,因为它在本地有效地序列化指令,所以它之前的所有加载都必须在它完成之前完成。
sfence仅序列化存储,它基本上不允许进程执行更多存储直到 sfence已退休。它还耗尽存储缓冲区。
mfence不是 两者的简单组合,因为它不是经典意义上的序列化,它是 sfence这也可以防止将来执行加载。
sfence可能一文不值是首先引入的,其他两个是后来引入的,以实现对内存排序的更细粒度的控制。

最后我习惯了关闭一个 rdtsc两个之间的指令 lfence说明,以确保不可能重新排序“向后”和“向前”。
但是我确信这种技术的可靠性。

关于assembly - LFENCE 的 x86-64 使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37452772/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com