Performance 针对简单阵列处理循环的AVX 512与AVX2性能

Performance 针对简单阵列处理循环的AVX 512与AVX2性能,performance,x86,micro-optimization,avx2,avx512,Performance,X86,Micro Optimization,Avx2,Avx512,我目前正在进行一些优化,并比较DSP应用程序的矢量化可能性,这似乎是AVX512的理想选择,因为这些只是简单的不相关阵列处理循环。但在一款新的i9上,与AVX2相比,使用AVX512时,我没有衡量出任何合理的改进。有什么建议吗?有什么好结果吗?(顺便说一句,我试过MSVC/CLANG/ICL,没有明显的区别,很多时候AVX512代码实际上看起来比较慢)这似乎太宽泛了,但实际上有一些微体系结构细节值得一提 请注意,AVX512-VL(向量长度)允许您在128位和256位向量上使用新的AVX512指

我目前正在进行一些优化,并比较DSP应用程序的矢量化可能性,这似乎是AVX512的理想选择,因为这些只是简单的不相关阵列处理循环。但在一款新的i9上,与AVX2相比,使用AVX512时,我没有衡量出任何合理的改进。有什么建议吗?有什么好结果吗?(顺便说一句,我试过MSVC/CLANG/ICL,没有明显的区别,很多时候AVX512代码实际上看起来比较慢)

这似乎太宽泛了,但实际上有一些微体系结构细节值得一提

请注意,AVX512-VL(向量长度)允许您在128位和256位向量上使用新的AVX512指令(如压缩
uint64_t
double
转换、掩码寄存器等)。现代编译器在为Skylake-AVX512(又称Skylake-X)进行调优时,通常会使用256位向量进行自动矢量化。例如,
gcc-march=native
gcc-march=Skylake-AVX512
,除非您覆盖调优选项,将代码的首选向量宽度设置为512,这样做是值得的。见@zam的答案


Skylake-X上使用512位向量(而不是使用AVX512指令的256位向量,如
vpxord ymm30、ymm29、ymm10
)的一些主要功能包括:

  • 将数据与矢量宽度对齐比使用AVX2更重要(每个未对齐的加载都会穿过缓存线边界,而不是在阵列上循环时每隔一次)。实际上,这会产生更大的不同。我完全忘记了我前一段时间测试的确切结果,但是可能是20%的减速,而不是不对齐导致的5%以下的减速

  • 运行512位UOP将关闭端口1上的向量ALU。(但不是端口1上的整数执行单元)。某些Skylake-X CPU(例如Xeon Bronze)每时钟只有1个512位FMA吞吐量,但i7/i9 Skylake-X CPU和高端Xeon在端口5上有一个额外的512位FMA单元,用于AVX512“模式”

    因此,要有相应的计划:从加宽到AVX512,您不会获得双倍的速度,代码中的瓶颈现在可能在后端

  • 运行512位UOP也会限制您的max Turbo,因此挂钟加速比可能低于核心时钟周期加速比。Turbo压缩有两个级别:任何512位操作,然后是重512位,就像持续的fma一样

  • vsqrtps/pd-zmm
    vdivps/pd
    的FP-divide执行单元不是全宽;它只有128位宽,因此div/sqrt与乘法吞吐量的比率差了大约2倍。看见
    vsqrtps xmm/ymm/zmm
    的SKX吞吐量为每3/6/12个周期一个
    double
    -精度是相同的比率,但吞吐量和延迟更差

    对于256位YMM向量,延迟与XMM相同(sqrt为12个周期),但对于512位ZMM,延迟增加到20个周期,需要3个UOP。(用于说明表。)

    如果您在除法器上遇到瓶颈,无法在混合中获得更多其他指令,
    VRSQRT14PS
    值得考虑,即使您需要牛顿迭代来获得足够的精度。但请注意,AVX512的近似值
    1/sqrt(x)
    确实比AVX/SSE具有更高的精度保证位。)


至于自动矢量化,如果需要任何洗牌,编译器可能会在更宽的矢量上做得更糟。对于简单的纯垂直内容,编译器可以使用AVX512

您前面的问题有一个
sin
函数,如果编译器/SIMD数学库只有该函数的256位版本,它可能不会使用AVX512自动矢量化

如果AVX512不起作用,可能是内存带宽瓶颈。使用性能计数器配置文件并查找。或者尝试以较小的缓冲区大小重复多次,看看当缓存中的数据处于热状态时,它是否会显著加快速度。如果是这样,请尝试缓存代码块,或者通过一次对数据执行更多操作来增加计算强度

AVX512在i9上的理论最大FMA吞吐量是原来的两倍(整数乘法,以及在同一执行单元上运行的许多其他操作),使DRAM和执行单元之间的不匹配增加了一倍。因此,更好地利用L2/L1d缓存可以获得两倍的收益

在数据已经加载到寄存器中的情况下处理数据是很好的。

对于ICL或GCC,您是如何编译(启用AVX512)代码的?AVX-512代码有两种“操作模式”:

  • 对于新的英特尔编译器(从18.0/17.0.5版开始),如果使用[Qa]xCORE-AVX512,您将只启用基本上意味着AVX512 ISA,但操作数为256位。这似乎也是GCC的默认行为
  • 否则,如果(a)使用较旧的英特尔编译器,或(b)使用[Qa]xCOMMON-AVX512或(c)使用特殊的新标志[Q/Q]opt zmm usage=high,您将获得具有512位宽操作数的完整AVX-512 ISA。(描述了给定的复杂标志逻辑)。在GCC8或更新版本的情况下,也可以使用-mprefer vector WITH=512启用此模式
  • 如果您的代码是“AVX512友好的”(您有很长的矢量化代码序列,没有“中断”矢量指令序列的标量代码片段),则模式(2)更可取,您必须启用它(默认情况下是而不是


    否则,如果您的代码对AVX512不太友好(矢量代码之间有许多非矢量化的代码段),那么由于SKX的“频率限制”,AVX512VL有时可能更有益(至少在您进行更多的代码矢量化之前),因此您应该确保在模式(1)下运行。例如,Lemier博士的博客中描述了频率与ISA的对比情况(尽管博客中给出的图片与现实相比有点过于夸张):和

    @BeeOnRope:缓存线交叉的额外延迟降低了OoO exec通过保持