因此 mov 本身的延迟应该是 1。
不,mov
是负载。数据也不需要经过 ALUmov
操作。
Agner Fog 的指令表不包含负载使用延迟(就像您正在测量的那样)。 它们在他的 microarch PDF 中,在每个 uarch 的“缓存和内存访问”部分的表格中。例如,SnB/IvB(第 9.13 节)有一个“1 级数据”行,其中包含“32 kB,8 路,64 B 行大小,延迟 4,每个内核”。
这 4 个周期的延迟是一系列相关指令的加载使用延迟,例如mov rax, [rax]
. 您正在测量 5 个周期,因为您使用的寻址模式不是[reg + 0..2047]
. 对于小的位移,加载单元推测直接使用基址寄存器作为 TLB 查找的输入将得到与使用加法器结果相同的结果。 当 base+offset 位于与 base 不同的页面时,是否会受到惩罚?. 因此,您的寻址模式[disp32 + rax]
使用正常路径,在加载端口中开始 TLB 查找之前再等待一个周期等待加法器结果。
对于不同域之间的大多数操作(例如整数寄存器和 XMM 寄存器),您只能真正测量类似movd xmm0,eax
/的往返行程mov eax, xmm0
,并且很难将其分开并弄清楚每条指令的延迟分别是多少1。
对于加载,您可以链接到另一个加载以测量缓存加载使用延迟,而不是存储/重新加载链。
出于某种原因,Agner 决定只查看他的表的存储转发延迟,并完全任意选择如何在存储和重新加载之间划分存储转发延迟。
(来自他的指令表电子表格的“术语定义”表,在介绍之后的左侧)
使用软件方法无法测量内存读取或写入指令的延迟。只能测量存储器写入和从同一地址读取存储器的组合延迟。这里测量的实际上并不是缓存访问时间,因为在大多数情况下,微处理器足够聪明,可以直接从写入单元到读取单元进行“存储转发”,而不是等待数据进入缓存再返回再次。
该存储转发过程的延迟在表中被任意分为写入延迟和读取延迟。但实际上,对性能优化有意义的唯一值是写入时间和读取时间的总和。
这显然是不正确的:L1d 加载使用延迟是指针追逐通过间接级别的事情。您可能会争辩说它只是可变的,因为某些负载可能会在缓存中丢失,但是如果您要选择要放入表中的内容,则最好选择 L1d 负载使用延迟。然后计算存储延迟数,使得存储+加载延迟=存储转发延迟,就像现在一样。英特尔凌动的存储延迟 = -2,因为它具有3c L1d 加载使用延迟,但根据 Agner 的 uarch 指南,它具有 1c 存储转发。
例如,这对于加载到 XMM 或 YMM 寄存器来说不太容易,但是一旦你计算出movq rax, xmm0
. x87 寄存器更难,因为没有办法直接从 ALU 中获取数据st0
/eax
通过rax
ALU,而不是存储/重新加载。但是也许您可以使用 FP 比较来做一些事情,例如fucomi
直接设置整数 FLAGS(在具有它的 CPU 上:P6 及更高版本)。
尽管如此,至少整数加载延迟来反映指针追逐延迟会好得多。IDK 如果有人提议为他更新 Agner 的表格,或者他是否愿意接受这样的更新。不过,需要对大多数 uarch 进行新的测试,以确保您对不同的寄存器集具有正确的加载使用延迟。
脚注 1:例如http://instlatx64.atw.hu没有尝试,只是在延迟列中显示“diff.reg.set”,仅在吞吐量列中显示有用的数据。但是他们有MOVD r64, xmm+MOVD xmm, r64
往返线路,在这种情况下,IvB 总共有 2 个周期,所以我们可以非常确信它们单程只有 1c。不是零一种方式。:P
但是对于加载到整数寄存器中,它们确实显示了 IvB 的 4 周期加载使用延迟MOV r32, [m32]
,因为显然它们使用[reg + 0..2047]
寻址模式进行测试。
https://uops.info/非常好,但在延迟方面给出了相当宽松的界限:IIRC,它们构造了一个往返循环(例如存储和重新加载,或 xmm->integer 和 integer->xmm),然后假设每隔一个步骤只有 1 个周期,给出延迟的上限。请参阅多个值或范围作为单个指令的延迟意味着什么?更多。
缓存延迟信息的其他来源:
https://www.7-cpu.com/有很多其他 uarch 的详细信息,甚至包括 ARM、MIPS、PowerPC 和 IA-64 等许多非 x86。
这些页面还有其他详细信息,例如缓存和 TLB 大小、TLB 时间、分支未命中实验结果和内存带宽。缓存延迟详细信息如下所示:
(来自他们的 Skylake 页面)
- L1 数据缓存延迟 = 4 个周期,用于通过指针进行简单访问
- L1 数据缓存延迟 = 5 个周期,用于复杂地址计算的访问 (
size_t n, *p; n = p[n]
)。
- L2 缓存延迟 = 12 个周期
- L3 缓存延迟 = 42 个周期(核心 0)(i7-6700 Skylake 4.0 GHz)
- L3 缓存延迟 = 38 个周期(i7-7700K 4 GHz,Kaby Lake)
- RAM 延迟 = 42 个周期 + 51 ns (i7-6700 Skylake)