如果运行大块,则吞吐量是倒数吞吐量just该指令。 (或者对于像这样的情况使用破坏依赖的指令adc
or div
由于隐式寄存器输入/输出(尤其是标志),您无法使背靠背执行不具有数据依赖性。所以0.5
意味着它可以每 0.5 个周期运行一次,即 2 个/时钟,正如我们所知道的具有 2 个负载端口的 CPU 所预期的那样。
为什么有时有两个延迟数字,例如[≤10;≤11]?
也可以看看多个值或范围作为单个指令的延迟意味着什么? https://stackoverflow.com/questions/60912850/what-do-multiple-values-or-ranges-means-as-the-latency-for-a-single-instruction以load+ALU ALU指令为例。 (我忘记了它有多接近重复,直到我写完这个答案的其余部分才寻找它。)
通常这表明从不同输入到输出的延迟可能不同。例如合并屏蔽加载必须合并到目标中,以便这是一个输入,加载地址是另一个输入(通过整数寄存器)。内存中最近存储的数据是第三个输入(存储转发延迟)。
对于矢量加载使用延迟等情况,加载结果与地址寄存器位于不同的域中,uops.info 创建一个依赖链,其指令序列涉及movd
or vmovq rax, xmm0
将加载结果耦合回另一个加载的地址。很难单独确定每个部分的延迟,因此 IIRC 他们假设链中的每个其他指令至少有 1 个周期,并将被测指令的延迟显示为<= N
,其中 N + dep 链的其余部分加起来就是测试代码每次迭代的总周期。
查看这些结果之一的详细信息页面,其中显示了用于测量它的测试序列。表中的每个数字也是一个链接。这些详细信息页面告诉您哪个操作数是哪个,并细分从每个输入到每个输出的延迟。让我们look at https://uops.info/html-lat/SKX/VMOVDQA64_Z_ZMM_K_M512-Measurements.html零掩码vmovdqa64
512 位负载(VMOVDQA64_Z (ZMM, K, M512)
)他们在 asm 中测试使用vmovdqa64 zmm0{k1}{z},ZMMWORD PTR [r14]
。列出的延迟是[1;≤9]
.
他们将操作数编号为
- 1(只写):ZMM 目的地。
- 2(只读):
k0..7
掩码寄存器
- 3(只读):内存(稍后分为地址与实际内存内容)
The 1
周期延迟部分是从掩码寄存器到结果的延迟,“延迟操作数2→1:1”。因此,在加载单元获取数据之前,掩码不必准备好。
The <=9
是从地址基址或索引寄存器到最终 ZMM 结果准备就绪的延迟。
显然,在存储/重新加载情况下,存储转发延迟成为瓶颈,“延迟操作数 3 → 1(内存):≤6”。他们用这个序列进行了测试,描述为“链延迟:≥6”。vshufpd zmm
已知有 1 个周期延迟,我猜他们只是将商店计算为有 1 个周期延迟?就像我说的,他们只是假设一切都是 1 个周期,尽管将任何延迟分配给存储有点可疑。
Code:
0: 62 d1 fd c9 6f 06 vmovdqa64 zmm0{k1}{z},ZMMWORD PTR [r14]
6: 62 71 fd 48 c6 e8 00 vshufpd zmm13,zmm0,zmm0,0x0
d: 62 51 95 48 c6 ed 00 vshufpd zmm13,zmm13,zmm13,0x0
14: 62 51 95 48 c6 ed 00 vshufpd zmm13,zmm13,zmm13,0x0
1b: 62 51 95 48 c6 ed 00 vshufpd zmm13,zmm13,zmm13,0x0
22: 62 51 95 48 c6 ed 00 vshufpd zmm13,zmm13,zmm13,0x0
29: 62 51 fd 48 11 2e vmovupd ZMMWORD PTR [r14],zmm13
(对于吞吐量测试,他们多次重复该块以创建展开的循环。但对于延迟测试,他们可能只是在其周围包裹一个正常的循环。nanobench 是开源的,因此您可以检查。)
对于“延迟操作数 3 → 1(地址、基址寄存器):≤9”测量,他们说“链延迟:≥5”。我们知道一个vmovq r,x
/ vmovq x,r
往返延迟超过 2 个周期,因此vmovq
这里的链条的一部分可能不仅仅是一个循环。这就是为什么他们高估了加载使用延迟,保守上限为 9 个周期。
0: 62 d1 fd c9 6f 06 vmovdqa64 zmm0{k1}{z},ZMMWORD PTR [r14]
6: c4 c1 f9 7e c4 vmovq r12,xmm0
b: 4d 31 e6 xor r14,r12
e: 4d 31 e6 xor r14,r12
11: 4d 31 e6 xor r14,r12
14: 4d 31 e6 xor r14,r12
他们测量:
- 已退役指令:6.0
- 核心周期:14.0
- 参考周期:10.81
- UOPS_EXECUTED.线程:7.0
每次迭代总共 14 个周期,因此他们计算出掩码负载所占的 14-5 = 9 个周期。 (或者如果链延迟实际上长于 5,则更少。vmovq
实际上可能是 3 或 4 个周期,因此 7 或 6 个周期的 SIMD 加载延迟听起来是正确的。我们知道整数加载使用延迟为 5 个周期,IIRC Intel 优化手册提到 SIMD 加载为 6 或 7 个周期。但我们真正能说的就是这个保守的上限 9sure纯粹基于测量,没有推断/猜测。)
AVX-512 指令命名。
“A64”是 AVX-512 的一部分vmovdqa64
指令助记符当然:查看Intel的asm手册:https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64 https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64。请记住,AVX-512 支持(几乎)每条指令的每元素合并或零掩码,因此即使movdqa
按位运算需要元素大小。这也是 AVX-512 按位布尔值的原因vpord
/ q
而不仅仅是vpor
(他们可以使用 b/w/d/q 命名 movdqa 元素大小,但我们会vmovdqad
or vmovdqaq
,但我想我们应该庆幸他们没有这么做。)
幸运的是,a32 与 a64 没有任何性能差异,只有当您使用掩码时,结果才会有任何差异,例如通过_mm512_maskz_load_epi32( __mmask16 k, void * sa)
与 epi64 相比,仅采用__mmask8
。或者对于较小的向量宽度,仅使用少于 8 位的掩码。
零掩码与合并掩码
op Z (ZMM, K, ZMM)
vs op (ZMM, K, ZMM)
是零掩蔽与合并掩蔽。如果您不知道 AVX-512 屏蔽的工作原理,请阅读相关内容。例如Kirill Yukhin 的演示幻灯片有一个概述:https://en.wikichip.org/w/images/d/d5/Intel_Advanced_Vector_Extensions_2015-2016_Support_in_GNU_Compiler_Collection.pdf https://en.wikichip.org/w/images/d/d5/Intel_Advanced_Vector_Extensions_2015-2016_Support_in_GNU_Compiler_Collection.pdf
Reg-reg vmovdqa 无屏蔽(无k
寄存器)可以是 0 延迟(mov-elimination),但使用屏蔽时它始终为 1。
有趣的事实:寄存器重命名k0..k7
使用与 MMX/x87 相同的物理寄存器文件空间:https://travisdowns.github.io/blog/2020/05/26/kreg2.html https://travisdowns.github.io/blog/2020/05/26/kreg2.html