如何解读uops.info?
How to interpret uops.info?
我在 uops.info 上查找了指令 VMOVDQA,试图弄清楚 (1) 什么是延迟,以及 (2) 我可以执行多少个并发加载?
我无法解释结果(下面的屏幕截图,上面也有链接):
- 指令的不同变体是什么意思?例如
A64 Z (ZMM, K, ZMM)
对比 A64 (ZMM, K, ZMM)
?
- 它似乎为参数提供了不同的类型,也许表明哪些参数在寄存器中?但是我不知道怎么读符号。
- 为什么有时会有两个延迟数字,例如
[≤10;≤11]
?这是否表示延迟范围,如果是,我可以计算出我的用例的确切延迟吗?
- 我应该如何解释吞吐量 (TP) 列?
非常感谢任何对此的指点!
如果 运行 宁 的大块只是 该指令,则吞吐量是倒数吞吐量。 (或者对于 adc
或 div
等情况下的 dependency-breaking 指令,由于隐式寄存器 inputs/outputs,您无法使 back-to-back 执行不具有数据依赖性,特别是旗帜)。所以 0.5
意味着它可以 运行 每 0.5 个周期一次,即 2/clock,正如我们所知道的具有 2 个加载端口的 CPU 所预期的那样。
Why are there sometimes two numbers for latency, e.g. [≤10;≤11]?
另请参阅,其中以加载+ALU ALU 指令为例。 (我忘记了重复的有多接近,直到我写完这个答案的其余部分才寻找它。)
通常这表示从不同输入到输出的延迟可能不同。例如merge-masking 加载必须合并到目标中,因此这是一个输入,加载地址是另一个输入(通过整数寄存器)。内存中的 recently-stored 数据是第三个输入(store-forwarding 延迟)。
对于向量 load-use 延迟这样的情况,其中加载结果与地址寄存器在不同的域中,uops.info 创建一个依赖链,其指令序列涉及 movd
或vmovq rax, xmm0
将加载结果耦合回另一个加载的地址。很难分别为每个部分建立延迟,因此 IIRC 他们假设链中的每个其他指令至少为 1 个周期,并将被测指令的延迟显示为 <= N
,其中 N + 其余部分dep 链加起来就是测试代码每次迭代的总周期数。
查看其中一个结果的详细信息页面,显示用于测量它的测试序列。 table 中的每个数字也是 link。这些详细信息页面会告诉您哪个操作数是哪个,并分解从每个输入到每个输出的延迟。让我们 look at zero-masked vmovdqa64
512 位负载(VMOVDQA64_Z (ZMM, K, M512)
),他们在 asm 中使用 vmovdqa64 zmm0{k1}{z},ZMMWORD PTR [r14]
进行了测试。列出的延迟为 [1;≤9]
.
他们将操作数编号为
- 1 (write-only): ZMM 目的地。
- 2 (read-only):
k0..7
掩码寄存器
- 3 (read-only): 内存(稍后分解为地址与实际内存内容)
1
周期延迟部分是从掩码寄存器到结果的延迟,“延迟操作数 2 → 1:1”。因此,在加载单元获取数据之前,掩码不必准备就绪。
<=9
是从地址基址或索引寄存器到准备好最终 ZMM 结果的延迟。
显然是 store/reload 情况,在 store-forwarding 延迟上出现瓶颈,“延迟操作数 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 是 open-source 所以你可以检查。)
对于“延迟操作数 3 → 1(地址,基址寄存器):≤9”测量,他们说“链延迟:≥5”。我们知道 vmovq r,x
/ vmovq x,r
round-trip 是超过 2 个周期的延迟,所以这里链的 vmovq
部分可能超过一个周期。这就是为什么他们 over-estimate load-use 延迟,保守上限为 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
他们测量:
- Instructions retired: 6.0
- Core cycles: 14.0
- Reference cycles: 10.81
- UOPS_EXECUTED.THREAD: 7.0
每次迭代总共 14 个周期,因此他们计算出 14-5 = 9 个周期被屏蔽负载所占。 (如果链延迟实际上长于 5,则更少。vmovq
实际上可能是 3 或 4 个周期,因此 7 或 6 个周期的 SIMD 加载延迟听起来是正确的。我们知道整数 load-use 延迟是 5 个周期, 和 IIRC Intel 的优化手册说 SIMD 负载是 6 或 7 个周期. 但是这个保守的上限 9 是我们真正可以说的 sure 纯粹基于测量, 没有外推 /猜测。)
AVX-512指令命名。
“A64”是AVX-512vmovdqa64
指令助记符的一部分,当然:查Intel的asm手册:https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64。请记住,AVX-512 在(几乎)每条指令上都支持 per-element 合并或 zero-masking,因此即使 movdqa
和按位运算也需要元素大小。这也是为什么 AVX-512 按位布尔值是 vpord
/ q
而不是 vpor
的原因(他们本可以使用 b/w/d/q 命名 movdqa 元素大小,但我们有vmovdqad
或 vmovdqaq
,但我想我们应该庆幸他们没有。)
幸运的是,a32 与 a64 没有任何性能差异,只有当您使用遮罩时,结果才会有任何差异,例如via _mm512_maskz_load_epi32( __mmask16 k, void * sa)
vs. epi64 只需要 __mmask8
。或者对于较小的矢量宽度,仅使用少于 8 位的掩码。
Zero-Masking 与合并掩码
op Z (ZMM, K, ZMM)
与 op (ZMM, K, ZMM)
是 zero-masking 与 merge-masking。如果哟不知道 AVX-512 掩蔽是如何工作的,请去阅读它。例如Kirill Yukhin 的演示幻灯片有一个概述:
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.
有趣的事实:register-renaming for k0..k7
使用与 MMX/x87 相同的物理寄存器文件 space:https://travisdowns.github.io/blog/2020/05/26/kreg2.html
我在 uops.info 上查找了指令 VMOVDQA,试图弄清楚 (1) 什么是延迟,以及 (2) 我可以执行多少个并发加载?
我无法解释结果(下面的屏幕截图,上面也有链接):
- 指令的不同变体是什么意思?例如
A64 Z (ZMM, K, ZMM)
对比A64 (ZMM, K, ZMM)
?- 它似乎为参数提供了不同的类型,也许表明哪些参数在寄存器中?但是我不知道怎么读符号。
- 为什么有时会有两个延迟数字,例如
[≤10;≤11]
?这是否表示延迟范围,如果是,我可以计算出我的用例的确切延迟吗? - 我应该如何解释吞吐量 (TP) 列?
非常感谢任何对此的指点!
如果 运行 宁 的大块只是 该指令,则吞吐量是倒数吞吐量。 (或者对于 adc
或 div
等情况下的 dependency-breaking 指令,由于隐式寄存器 inputs/outputs,您无法使 back-to-back 执行不具有数据依赖性,特别是旗帜)。所以 0.5
意味着它可以 运行 每 0.5 个周期一次,即 2/clock,正如我们所知道的具有 2 个加载端口的 CPU 所预期的那样。
Why are there sometimes two numbers for latency, e.g. [≤10;≤11]?
另请参阅
通常这表示从不同输入到输出的延迟可能不同。例如merge-masking 加载必须合并到目标中,因此这是一个输入,加载地址是另一个输入(通过整数寄存器)。内存中的 recently-stored 数据是第三个输入(store-forwarding 延迟)。
对于向量 load-use 延迟这样的情况,其中加载结果与地址寄存器在不同的域中,uops.info 创建一个依赖链,其指令序列涉及 movd
或vmovq rax, xmm0
将加载结果耦合回另一个加载的地址。很难分别为每个部分建立延迟,因此 IIRC 他们假设链中的每个其他指令至少为 1 个周期,并将被测指令的延迟显示为 <= N
,其中 N + 其余部分dep 链加起来就是测试代码每次迭代的总周期数。
查看其中一个结果的详细信息页面,显示用于测量它的测试序列。 table 中的每个数字也是 link。这些详细信息页面会告诉您哪个操作数是哪个,并分解从每个输入到每个输出的延迟。让我们 look at zero-masked vmovdqa64
512 位负载(VMOVDQA64_Z (ZMM, K, M512)
),他们在 asm 中使用 vmovdqa64 zmm0{k1}{z},ZMMWORD PTR [r14]
进行了测试。列出的延迟为 [1;≤9]
.
他们将操作数编号为
- 1 (write-only): ZMM 目的地。
- 2 (read-only):
k0..7
掩码寄存器 - 3 (read-only): 内存(稍后分解为地址与实际内存内容)
1
周期延迟部分是从掩码寄存器到结果的延迟,“延迟操作数 2 → 1:1”。因此,在加载单元获取数据之前,掩码不必准备就绪。
<=9
是从地址基址或索引寄存器到准备好最终 ZMM 结果的延迟。
显然是 store/reload 情况,在 store-forwarding 延迟上出现瓶颈,“延迟操作数 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 是 open-source 所以你可以检查。)
对于“延迟操作数 3 → 1(地址,基址寄存器):≤9”测量,他们说“链延迟:≥5”。我们知道 vmovq r,x
/ vmovq x,r
round-trip 是超过 2 个周期的延迟,所以这里链的 vmovq
部分可能超过一个周期。这就是为什么他们 over-estimate load-use 延迟,保守上限为 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
他们测量:
- Instructions retired: 6.0
- Core cycles: 14.0
- Reference cycles: 10.81
- UOPS_EXECUTED.THREAD: 7.0
每次迭代总共 14 个周期,因此他们计算出 14-5 = 9 个周期被屏蔽负载所占。 (如果链延迟实际上长于 5,则更少。vmovq
实际上可能是 3 或 4 个周期,因此 7 或 6 个周期的 SIMD 加载延迟听起来是正确的。我们知道整数 load-use 延迟是 5 个周期, 和 IIRC Intel 的优化手册说 SIMD 负载是 6 或 7 个周期. 但是这个保守的上限 9 是我们真正可以说的 sure 纯粹基于测量, 没有外推 /猜测。)
AVX-512指令命名。
“A64”是AVX-512vmovdqa64
指令助记符的一部分,当然:查Intel的asm手册:https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64。请记住,AVX-512 在(几乎)每条指令上都支持 per-element 合并或 zero-masking,因此即使 movdqa
和按位运算也需要元素大小。这也是为什么 AVX-512 按位布尔值是 vpord
/ q
而不是 vpor
的原因(他们本可以使用 b/w/d/q 命名 movdqa 元素大小,但我们有vmovdqad
或 vmovdqaq
,但我想我们应该庆幸他们没有。)
幸运的是,a32 与 a64 没有任何性能差异,只有当您使用遮罩时,结果才会有任何差异,例如via _mm512_maskz_load_epi32( __mmask16 k, void * sa)
vs. epi64 只需要 __mmask8
。或者对于较小的矢量宽度,仅使用少于 8 位的掩码。
Zero-Masking 与合并掩码
op Z (ZMM, K, ZMM)
与 op (ZMM, K, ZMM)
是 zero-masking 与 merge-masking。如果哟不知道 AVX-512 掩蔽是如何工作的,请去阅读它。例如Kirill Yukhin 的演示幻灯片有一个概述:
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.
有趣的事实:register-renaming for k0..k7
使用与 MMX/x87 相同的物理寄存器文件 space:https://travisdowns.github.io/blog/2020/05/26/kreg2.html