英特尔较新架构的控制指令和移动指令延迟是多少?
What are the control instructions and move instructions latency for Intel's newer architectures?
我正在查看 Intel Architectures Optimization Reference Manual 2017(第 759 页)。我正在寻找 Haswell 和 Skylake 架构。 MOV, PUSH, JMP, CALL
指令在 table 中有意省略。没有给出延迟信息。这是为什么?虽然,第 776 页上的 Atom 处理器给出了这些指令延迟。
有趣的是,英特尔的 2012 optimization manual 有 MOV
、PUSH
和 CALL
指令延迟。
Agner 的 instruction tables 为 MOV
和 PUSH
提供延迟,但跳过 JMP
和 CALL
等控制指令。知道这是为什么吗?
简短的回答是,对于控制指令和孤立的许多类型的 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).
当我们谈论指令的延迟时,我们通常指的是从其输入中产生结果所花费的时间,而不是在给定的时间段内可以产生多少结果。这就是生一个孩子需要 9 个月(潜伏期)和一个城市一个月生 100 个孩子(吞吐量)之间的区别。
测量延迟的常用方法是将一系列指令链接在一起,其中一个指令的输出用作下一个指令的输入。由于它们是相关的,因此您可以测量延迟,因为它们是串行执行的。例如,如果您想测量 add
的延迟,您可以使用如下序列:
add eax, eax
add eax, eax
add eax, eax
...
注意输出寄存器 eax
如何在输入中反馈到下一个 add
。
现在,控制流指令没有明显的显式 "output" 可以反馈到它们的输入中。他们的输出是指令流的变化,但不清楚如何将其反馈到下一条指令中。此外,控制流的整个机制通常被分离到一个分支预测引擎中,该引擎试图在控制流指令执行之前很久就正确地引导前端,在延迟方面进一步混淆了水域。
充其量您可以谈论这些构造的吞吐量:现代英特尔通常每个周期可以执行两个分支,最多可以执行其中一个。
您 运行 遇到与内存中的 mov
指令相同的问题。在这里,输出和输入很清楚,但它们位于不同的域(寄存器与内存)。因此,您不必将存储指令的输出提供给后续存储指令,因为存储有 "memory" 输出但 "register" 输入。您可以做的是在同一位置将成对的加载和存储指令链接在一起,并获得该对的组合延迟:根据寻址模式和其他因素,现代英特尔通常需要 运行 3 到 7 个周期。
特别是对于加载,你可以在下一次加载的地址计算中使用加载的结果(寄存器域),给你一个 load-to-load-address 延迟(有人称之为 load-to-use ,但我认为这令人困惑),这在现代英特尔上通常最多是 4 个周期,对于复杂的寻址模式或向量加载,每个周期都需要 1 个额外的周期。
对于寄存器到寄存器的移动,延迟通常为零个周期(由于移动消除),或者当移动无法消除时为 1 个周期。
这些问题可能是您在 Intel 指南甚至其他指南(如 Agner 的指南)中看不到这些构造的延迟数据的原因。
我正在查看 Intel Architectures Optimization Reference Manual 2017(第 759 页)。我正在寻找 Haswell 和 Skylake 架构。 MOV, PUSH, JMP, CALL
指令在 table 中有意省略。没有给出延迟信息。这是为什么?虽然,第 776 页上的 Atom 处理器给出了这些指令延迟。
有趣的是,英特尔的 2012 optimization manual 有 MOV
、PUSH
和 CALL
指令延迟。
Agner 的 instruction tables 为 MOV
和 PUSH
提供延迟,但跳过 JMP
和 CALL
等控制指令。知道这是为什么吗?
简短的回答是,对于控制指令和孤立的许多类型的 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).
当我们谈论指令的延迟时,我们通常指的是从其输入中产生结果所花费的时间,而不是在给定的时间段内可以产生多少结果。这就是生一个孩子需要 9 个月(潜伏期)和一个城市一个月生 100 个孩子(吞吐量)之间的区别。
测量延迟的常用方法是将一系列指令链接在一起,其中一个指令的输出用作下一个指令的输入。由于它们是相关的,因此您可以测量延迟,因为它们是串行执行的。例如,如果您想测量 add
的延迟,您可以使用如下序列:
add eax, eax
add eax, eax
add eax, eax
...
注意输出寄存器 eax
如何在输入中反馈到下一个 add
。
现在,控制流指令没有明显的显式 "output" 可以反馈到它们的输入中。他们的输出是指令流的变化,但不清楚如何将其反馈到下一条指令中。此外,控制流的整个机制通常被分离到一个分支预测引擎中,该引擎试图在控制流指令执行之前很久就正确地引导前端,在延迟方面进一步混淆了水域。
充其量您可以谈论这些构造的吞吐量:现代英特尔通常每个周期可以执行两个分支,最多可以执行其中一个。
您 运行 遇到与内存中的 mov
指令相同的问题。在这里,输出和输入很清楚,但它们位于不同的域(寄存器与内存)。因此,您不必将存储指令的输出提供给后续存储指令,因为存储有 "memory" 输出但 "register" 输入。您可以做的是在同一位置将成对的加载和存储指令链接在一起,并获得该对的组合延迟:根据寻址模式和其他因素,现代英特尔通常需要 运行 3 到 7 个周期。
特别是对于加载,你可以在下一次加载的地址计算中使用加载的结果(寄存器域),给你一个 load-to-load-address 延迟(有人称之为 load-to-use ,但我认为这令人困惑),这在现代英特尔上通常最多是 4 个周期,对于复杂的寻址模式或向量加载,每个周期都需要 1 个额外的周期。
对于寄存器到寄存器的移动,延迟通常为零个周期(由于移动消除),或者当移动无法消除时为 1 个周期。
这些问题可能是您在 Intel 指南甚至其他指南(如 Agner 的指南)中看不到这些构造的延迟数据的原因。