gpt4 book ai didi

performance - Haswell AVX/FMA 延迟测试比英特尔指南慢 1 个周期

转载 作者:行者123 更新时间:2023-12-02 19:12:14 27 4
gpt4 key购买 nike

在英特尔内部函数指南中,vmulpdvfmadd213pd延迟为 5,vaddpd延迟为 3。

我编写了一些测试代码,但所有结果都慢了 1 个周期。

这是我的测试代码:

.CODE
test_latency PROC
vxorpd ymm0, ymm0, ymm0
vxorpd ymm1, ymm1, ymm1

loop_start:
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
sub rcx, 4
jg loop_start

ret
test_latency ENDP
END
#include <stdio.h>
#include <omp.h>
#include <stdint.h>
#include <windows.h>

extern "C" void test_latency(int64_t n);

int main()
{
SetThreadAffinityMask(GetCurrentThread(), 1); // Avoid context switch

int64_t n = (int64_t)3e9;
double start = omp_get_wtime();
test_latency(n);
double end = omp_get_wtime();
double time = end - start;

double freq = 3.3e9; // My CPU frequency
double latency = freq * time / n;
printf("latency = %f\n", latency);
}

我的CPU是Core i5 4590,我将其频率锁定在3.3GHz。输出为:latency = 6.102484 .

奇怪的是,如果我改变 vmulpd ymm0, ymm0, ymm1vmulpd ymm0, ymm0, ymm0 ,则输出变为:latency = 5.093745 .

有解释吗?我的测试代码有问题吗?

更多结果

results on Core i5 4590 @3.3GHz
vmulpd ymm0, ymm0, ymm1 6.056094
vmulpd ymm0, ymm0, ymm0 5.054515
vaddpd ymm0, ymm0, ymm1 4.038062
vaddpd ymm0, ymm0, ymm0 3.029360
vfmadd213pd ymm0, ymm0, ymm1 6.052501
vfmadd213pd ymm0, ymm1, ymm0 6.053163
vfmadd213pd ymm0, ymm1, ymm1 6.055160
vfmadd213pd ymm0, ymm0, ymm0 5.041532

(without vzeroupper)
vmulpd xmm0, xmm0, xmm1 6.050404
vmulpd xmm0, xmm0, xmm0 5.042191
vaddpd xmm0, xmm0, xmm1 4.044518
vaddpd xmm0, xmm0, xmm0 3.024233
vfmadd213pd xmm0, xmm0, xmm1 6.047219
vfmadd213pd xmm0, xmm1, xmm0 6.046022
vfmadd213pd xmm0, xmm1, xmm1 6.052805
vfmadd213pd xmm0, xmm0, xmm0 5.046843

(with vzeroupper)
vmulpd xmm0, xmm0, xmm1 5.062350
vmulpd xmm0, xmm0, xmm0 5.039132
vaddpd xmm0, xmm0, xmm1 3.019815
vaddpd xmm0, xmm0, xmm0 3.026791
vfmadd213pd xmm0, xmm0, xmm1 5.043748
vfmadd213pd xmm0, xmm1, xmm0 5.051424
vfmadd213pd xmm0, xmm1, xmm1 5.049090
vfmadd213pd xmm0, xmm0, xmm0 5.051947

(without vzeroupper)
mulpd xmm0, xmm1 5.047671
mulpd xmm0, xmm0 5.042176
addpd xmm0, xmm1 3.019492
addpd xmm0, xmm0 3.028642

(with vzeroupper)
mulpd xmm0, xmm1 5.046220
mulpd xmm0, xmm0 5.057278
addpd xmm0, xmm1 3.025577
addpd xmm0, xmm0 3.031238

我的猜测

我改变了test_latency像这样:

.CODE
test_latency PROC
vxorpd ymm0, ymm0, ymm0
vxorpd ymm1, ymm1, ymm1

loop_start:
vaddpd ymm1, ymm1, ymm1 ; added this line
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
vmulpd ymm0, ymm0, ymm1
sub rcx, 4
jg loop_start

ret
test_latency ENDP
END

终于得到了5个循环的结果。还有其他指令可以达到同样的效果:

vmovupd     ymm1, ymm0
vmovupd ymm1, [mem]
vmovdqu ymm1, [mem]
vxorpd ymm1, ymm1, ymm1
vpxor ymm1, ymm1, ymm1
vmulpd ymm1, ymm1, ymm1
vshufpd ymm1, ymm1, ymm1, 0

但是这些说明不能:

vmovupd     ymm1, ymm2  ; suppose ymm2 is zeroed
vpaddq ymm1, ymm1, ymm1
vpmulld ymm1, ymm1, ymm1
vpand ymm1, ymm1, ymm1

对于 ymm 指令,我猜想避免 1 个额外周期的条件是:

  1. 所有输入都来自同一域。
  2. 所有输入都足够新鲜。 (从旧值移动不起作用)

至于VEX xmm,情况似乎有点模糊。好像和上半状态有关,但不知道哪个更干净:

vxorpd      ymm1, ymm1, ymm1
vxorpd xmm1, xmm1, xmm1
vzeroupper

这个问题对我来说很难。

最佳答案

自从在 Skylake 上注意到它以来,我几年来一直想写一些关于这个的东西。 https://github.com/travisdowns/uarch-bench/wiki/Intel-Performance-Quirks#after-an-integer-to-fp-bypass-latency-can-be-increased-indefinitely

旁路延迟延迟是“粘性的”:整数 SIMD 指令可以“感染”读取该值的所有 future 指令,即使在指令完成很长时间之后也是如此。我很惊讶“感染”在归零惯用法中幸存下来,尤其是像 vxorpd 这样的 FP 归零指令。 ,但我可以在 SKL 上重现这种效果(i7-6700k,在 Linux 上使用 perf 直接在测试循环中计算时钟周期,而不是搞乱时间和频率。)

(在 Skylake 上,在循环发生工作之前,似乎有 3 个或更多 vxorpd 连续归零指令,从而消除了额外的旁路延迟。据我所知,异或归零总是被消除,这与mov-elimination 有时会失败。但也许区别只是在后端的 vpaddb 和第一个 vmulpd 之间创建了一个间隙;在我的测试循环中,我“脏”/污染了之前的寄存器循环。)

(更新:现在再次尝试我的测试代码,即使是 vxorps 似乎也清理了寄存器。也许微代码更新改变了一些东西。)

推测调用者中 YMM1 的某些先前使用涉及整数指令。 (TODO:调查寄存器进入这种状态的常见情况,以及它何时可以在异或归零中幸存!我预计它只会在使用整数指令构造 FP 位模式时发生,包括像 vpcmpeqd ymm1,ymm1,ymm1 这样的东西创建一个 -NaN(全 1 位)。)

在 Skylake 上,我可以通过执行 vaddpd ymm1, ymm1, ymm1 来修复它循环之前,异或归零之后。 (或者之前;这可能并不重要!这可能是更优化的,将其放在前一个 dep 链的末尾而不是这个的开头。)


正如我所写的in a comment on another question

xsave/rstor can fix the issue where writing a register with aSIMD-integer instruction like paddd creates extra latency indefinitelyfor reading it with an FP instruction, affecting latency from bothinputs. e.g. paddd xmm0, xmm0 then in a loop addps xmm1, xmm0 has 5clatency instead of the usual 4, until the next save/restore.

It'sbypass latency but still happens even if you don't touch the registeruntil after the paddd has definitely retired (by padding with >ROBuops) before the loop.


测试程序:

; taskset -c 3 perf stat --all-user -etask-clock,context-switches,cpu-migrations,page-faults,cycles,branches,instructions,uops_issued.any,uops_executed.thread -r1 ./bypass-latency

default rel
global _start
_start:
vmovaps xmm1, [one] ; FP load into ymm1 (zeroing the upper lane)
vpaddd ymm1, ymm1,ymm0 ; ymm1 written in the ivec domain
;vxorps ymm1, ymm1,ymm1 ; In 2017, ymm1 still makes vaddps slow (5c) after this
; but I can't reproduce that now with updated microcode.
vxorps ymm0, ymm0, ymm0 ; zeroing-idiom on ymm0
mov rcx, 50000000

align 32 ; doesn't help or hurt, as expected since the bottleneck isn't frontend
.loop:
vaddps ymm0, ymm0,ymm1
vaddps ymm0, ymm0,ymm1
dec rcx
jnz .loop

xor edi,edi
mov eax,231
syscall ; exit_group(0)

section .rodata
align 16
one: times 4 dd 1.0

Perf 在 i7-6700k 上生成静态可执行文件:

 Performance counter stats for './foo' (4 runs):

129.01 msec task-clock # 0.998 CPUs utilized ( +- 0.51% )
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.016 K/sec
500,053,798 cycles # 3.876 GHz ( +- 0.00% )
50,000,042 branches # 387.576 M/sec ( +- 0.00% )
200,000,059 instructions # 0.40 insn per cycle ( +- 0.00% )
150,020,084 uops_issued.any # 1162.883 M/sec ( +- 0.00% )
150,014,866 uops_executed.thread # 1162.842 M/sec ( +- 0.00% )

0.129244 +- 0.000670 seconds time elapsed ( +- 0.52% )

500M 迭代的 500M 周期 = 2x 10 周期循环携带依赖 vaddps ,或各 5 个。

关于performance - Haswell AVX/FMA 延迟测试比英特尔指南慢 1 个周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64116679/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com