x86 - 英特尔较新架构的控制指令和移动指令延迟是多少?

标签 x86 intel machine-code micro-architecture

我正在查看Intel Architectures Optimization Reference Manual 2017 (第 759 页)。我正在寻找 Haswell 和 Skylake 架构。该表中故意省略了 MOV、PUSH、JMP、CALL 指令。没有给出延迟信息。这是为什么?尽管如此,第 776 页上给出了 Atom 处理器的指令延迟。

有趣的是 2012 optimization manual来自英特尔的指令有 MOVPUSHCALL 指令延迟。

阿格纳的instruction tablesMOVPUSH 提供延迟,但会跳过 JMPCALL 等控制指令。知道为什么吗?

最佳答案

简单的回答是,对于控制指令以及许多类型的独立 mov 指令来说,在实践中延迟实际上并不是一个有意义的指标。

在您提到的评论中:

I was referring to Intel's manual for control instructions. What I mean by average latency for control instructions is that we get some data for number of instructions retired over a period of time and then take time/(number of instructions).

当我们谈论指令的延迟时,我们通常指的是从输入生成结果所需的时间,而不是多少个结果可以在给定的时间内生产。这相当于在一个城市生一个 child 需要 9 个月(延迟)与一个月内出生 100 个婴儿(吞吐量)之间的差异。

测量延迟的常用方法是将一系列指令链接在一起,其中一条指令的输出用作下一条指令的输入。由于它们是相关的,因此您会得到延迟测量,因为它们是串行执行的。例如,如果您想测量 add 的延迟,您可以使用如下序列:

add eax, eax
add eax, eax
add eax, eax
...

注意输出寄存器eax如何在输入中反馈到下一个add

现在,控制流指令没有明显的显式“输出”可以反馈到其输入中。它们的输出是指令流的变化,但尚不清楚如何将其反馈到下一条指令中。此外,控制流的整个机制通常被解耦到分支预测引擎中,该引擎试图在执行控制流指令之前正确引导前端,从而在延迟方面进一步困惑。

您最多可以谈论这些结构的吞吐量:现代英特尔通常可以每个周期执行两个分支,最多可以采用其中一个。

您在使用 mov 指令传入或传出内存时遇到了同样的问题。在这里,输出和输入是明确的,但它们位于不同的域(寄存器与内存)。因此,您不一定将存储指令的输出提供给后续存储指令,因为存储具有“内存”输出但“寄存器”输入。您可以做的是将同一位置上的加载和存储指令对链接在一起,并获得该对的组合延迟:在现代 Intel 上,这通常运行 3 到 7 个周期,具体取决于寻址模式和其他因素。

特别是对于加载,您可以在下一次加载的地址计算中使用加载的结果(寄存器域),从而给您带来加载到加载地址的延迟(有些人称之为加载到使用) ,但我认为这令人困惑),在现代英特尔上通常最多 4 个周期,对于复杂的寻址模式或向量加载,每个周期还需要 1 个额外的周期。

对于寄存器到寄存器的移动,延迟通常为 0 个周期(由于 mov 消除),或者当 mov 无法消除时为 1 个周期。

这些问题可能就是您在英特尔指南甚至 Agner 等其他指南中看不到这些结构的延迟数据的原因。

关于x86 - 英特尔较新架构的控制指令和移动指令延迟是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49306693/

相关文章:

c++ - 在我的 C++ 程序中寻找一些输入。 Simpletron,机器语言

assembly - 带段寄存器的 x86-64 MOV 指令上的 REX.W 前缀

assembly - 直接读取程序计数器

c - 排空Intel Core 2 Duo 的指令流水线?

memory - 页表条目中的 x86 脏位

c++ - ARM原子性能

html - 使用英特尔应用程序框架进行离线缓存?

Windows 初始执行上下文

c++ - std::function<> 和 Intel 编译器版本 11.1

assembly - 如何将机器指令解码为 LEGv8 中的汇编语言?