最初,我试图重现 Agner Fog 的微架构指南部分“YMM 和 ZMM 向量指令的预热期”中描述的效果,其中写道:
处理器在不使用时关闭向量执行单元的上部部分,以节省电力。在大约 56,000 个时钟周期或 14 μs 的初始预热期间,具有 256 位向量的指令的吞吐量大约比正常情况慢 4.5 倍。
我得到了减速,尽管看起来更接近 2 倍而不是 4.5 倍。但我发现在我的 CPU(Intel i7-9750H Coffee Lake)上,速度下降不仅影响 256 位操作,还影响 128 位向量操作和标量浮点操作(甚至 N 个仅 GPR 的操作) XMM 触摸指令之后的指令)。
基准程序代码:
# Compile and run:
# clang++ ymm-throttle.S && ./a.out
.intel_syntax noprefix
.data
L_F0:
.asciz "ref cycles = %u\n"
.p2align 5
L_C0:
.long 1
.long 2
.long 3
.long 4
.long 1
.long 2
.long 3
.long 4
.text
.set initial_scalar_warmup, 5*1000*1000
.set iteration_count, 30*1000
.set wait_count, 50*1000
.global _main
_main:
# ---------- Initial warm-up
# It seems that we enter _main (at least in MacOS 11.2.2) in a "ymm warmed-up" state.
#
# Initial warm-up loop below is long enough for the processor to switch back to
# "ymm cold" state. It also may reduce dynamic-frequency scaling related measurements
# deviations (hopefully CPU is in full boost by the time we finish initial warmup loop).
vzeroupper
push rbp
mov ecx, initial_scalar_warmup
.p2align 4
_initial_loop:
add eax, 1
add edi, 1
add edx, 1
dec ecx
jnz _initial_loop
# --------- Measure XMM
# TOUCH YMM.
# Test to see effect of touching unrelated YMM register
# on XMM performance.
# If "vpxor ymm9" below is commented out, then the xmm_loop below
# runs a lot faster (~2x faster).
vpxor ymm9, ymm9, ymm9
mov ecx, iteration_count
rdtsc
mov esi, eax
vpxor xmm0, xmm0, xmm0
vpxor xmm1, xmm1, xmm1
vpxor xmm2, xmm2, xmm2
vmovdqa xmm3, [rip + L_C0]
.p2align 5
_xmm_loop:
# Here we only do XMM (128-bit) VEX-encoded op. But it is triggering execution throttling.
vpaddd xmm0, xmm3, xmm3
add edi, 1
add eax, 1
dec ecx
jnz _xmm_loop
lfence
rdtsc
sub eax, esi
mov esi, eax # ESI = ref cycles count
# ------------- Print results
lea rdi, [rip + L_F0]
xor eax, eax
call _printf
vzeroupper
xor eax, eax
pop rbp
ret
Question:我的基准正确吗?对正在发生的事情的描述(如下)看起来合理吗?
CPU 处于 AVX 冷状态(约 675 µs 内未执行 256 位/512 位指令)遇到带有 YMM (ZMM) 目标寄存器的单个指令。 CPU 立即切换到某种“过渡到 AVX-warm”状态。 Agner 指南中提到,这大概需要大约 100-200 个周期。这个“过渡”期持续约 56'000 个周期。
在过渡期间,GPR 代码可以正常执行,但任何具有向量目标寄存器的指令(包括 128 位 XMM 或标量浮点指令,甚至包括vmovq xmm0, rax
) 将限制应用于整个执行管道。这会影响紧随此类指令的 N 个周期的仅 GPR 代码(不确定有多少;可能相当于指令的十几个周期)。
也许限制会限制分派到执行单元的微操作数(无论这些微操作是什么;只要至少有一个带有向量目标寄存器的微操作)?
对我来说,这里的新内容是,我认为在过渡期间限制将仅适用于 256 位(和 512 位)指令,但似乎任何具有向量寄存器目标的指令都会受到影响(以及〜20- 60 的探地雷达 - 仅立即遵循说明;无法在我的系统上进行更精确的测量)。
相关:“仅电压转换”部分Travis Downs 博客上的一篇文章可能正在描述相同的效果。尽管作者在过渡期间测量了 YMM 向量的性能,但得出的结论是,并不是向量的上半部分被分割,而是在过渡期间遇到向量寄存器接触指令时对整个流水线进行了限制。 (编辑:博客文章没有在过渡期间测量 XMM 寄存器,而这正是本文所测量的)。