Nan*_*mbe 1 icc compiler-optimization avx2 xeon-phi avx512
在尝试学习Coursera 上的课程时,我尝试为我的 CPU 优化示例 C++ 代码Intel i5-8259U,我相信它支持AVX2SIMD 指令集。现在,AVX2每个内核提供 16 个寄存器(称为YMM0, YMM1, ..., YMM15),宽度为 256 位,这意味着每个内核最多可以同时处理 4 个双精度浮点数。利用AVX2SIMD 指令应该可以优化我的代码,使其运行速度比标量指令快 4 倍。
在链接的课程中,您可以尝试在Intel Xeon Phi 7210 (Knights Landing)支持AVX512使用 512 位宽寄存器的处理器上运行相同的数值积分代码。这意味着我们应该期望双精度运算的速度提高 8 倍。实际上,讲师使用的代码获得了高达 14 倍的优化,几乎是 8 的 173%。额外的优化归功于 OpenMP。
为了在我的 CPU 上运行相同的代码,我唯一改变的是传递给英特尔编译器的优化标志:-xMIC-AVX512我使用了 ,而不是-xCORE-AVX2。我获得的加速仅为 2 倍,仅是由于 256 位寄存器上的 SIMD 矢量化而产生的预期加速的 50%。将此 50% 与英特尔至强融核处理器上获得的 173% 进行比较。
为什么我仅仅从 转到 就看到性能的巨大AVX512损失AVX2?当然,除了 SIMD 优化之外,还有其他因素在起作用。我缺少什么?
integral/solutions/1-simd/ PS 您可以在此处的文件夹中找到引用的代码。
TL:DR: KNL(Knight's Landing)只擅长运行专门为其编译的代码,因此获得更大的加速,因为它在运行“通用”代码时遇到了严重的问题。
从 128 位 SSE2 到 256 位 AVX,Coffee Lake 仅获得 2 倍的加速,同时以最佳方式运行“通用”代码和目标代码。
像 Coffee Lake 这样的主流 CPU 是现代编译器中“通用”调优关心的目标之一,而且它们总体上没有太多弱点。但 KNL 不是;没有任何选项的ICC不关心KNL
您假设加速的基线是标量。但如果没有任何像-march=native或 之类的选项-xCORE-AVX2,英特尔编译器 (ICC) 仍将使用 SSE2 自动矢量化,因为这是 x86-64 的基准。
-xCORE-AVX2不启用自动矢量化,它只是为自动矢量化提供更多可使用的指令。-O0优化级别(包括自动矢量化)由//控制,对于 FP 由 strict 与 fast-O2控制。英特尔的编译器默认使用(比 低一级)进行完全优化,因此它类似于.-O3fp-model-fp-model fast=1fast=2gcc -O3 -ffast-math
但如果没有额外的选项,它只能使用基线指令集,对于 x86-64 来说是 SSE2。这仍然比标量更好。
SSE2 使用 128 位 XMM 寄存器进行打包双精度数学,其指令吞吐量与 AVX(在 i5 Coffee Lake 上)相同,但每条指令的工作量只有一半。(而且它没有 FMA,因此编译器无法将源代码中的任何 mul+add 操作收缩为 FMA 指令,就像 AVX+FMA 那样)。
因此,对于一个纯粹是向量 mul/add/FMA SIMD 吞吐量(不是内存/缓存或其他任何东西)的瓶颈的简单问题,您的 Coffee Lake CPU 的 2 倍加速正是您所期望的。
加速取决于您的代码正在做什么。如果内存或缓存带宽出现瓶颈,更宽的寄存器只能帮助更好地利用内存并行性并使其保持饱和。
AVX + AVX2 添加了更强大的洗牌和混合以及其他很酷的东西,但对于纯垂直 SIMD 的简单问题没有帮助。
所以真正的问题是为什么 AVX512 对 KNL 的帮助超过 4 倍? Knight's Landing 上的每条 AVX512 SIMD 指令有8 个double元素(SSE2 为 2 个),如果指令吞吐量相同,预期加速将达到 4 倍。假设总指令数与 AVX512 相同。(事实并非如此:对于相同的循环展开,每个循环开销的向量工作量随着更宽的向量以及其他因素而增加。)
如果不知道您正在编译什么源代码,很难确定。AVX512 添加了一些可能有助于保存指令的功能,例如广播内存源操作数,而不需要将单独的广播加载到寄存器中。
如果您的问题涉及任何除法,KNL 的全精度 FP 除法非常慢,通常应该使用AVX512ER 近似指令(28 位精度) + Newton-Raphson 迭代(一对 FMA + mul)将其加倍,从而接近到完整double(53 位有效数,包括 1 个隐式位)。 -xMIC-AVX512启用 AVX512ER,并设置调整选项,以便 ICC 实际上选择使用它。
(相比之下,Coffee Lake AVX 256 位除法吞吐量并不比每周期翻倍的 128 位除法吞吐量好多少,但如果没有 AVX512ER,就没有一种有效的方法来使用 Newton-Raphson)double。请参阅浮点除法与浮点乘法- Skylake 数字适用于您的 Coffee Lake。
AVX / AVX512 可以避免额外的movaps指令来复制寄存器,这对 KNL 有很大帮助(每条不是 mul/add/FMA 的指令都会消耗 FP 吞吐量,因为它有 2 个每个时钟的 FMA,但每个时钟最多只有 2 个)指令吞吐量)。(https://agner.org/optimize/)
KNL 基于 Silvermont 低功耗核心(这就是他们如何将如此多的核心安装到一个芯片上)。
相比之下,Coffee Lake 具有更强大的前端和后端执行吞吐量:它每时钟有 2 个 FMA/mul/add,但每个时钟有 4 个总指令吞吐量,因此有空间运行一些非 FMA 指令,而无需减少 FMA 吞吐量。
KNL 是专门为运行 AVX512 代码而构建的。他们没有浪费晶体管,使其能够有效地运行不是专门为其编译的遗留代码(使用-xMIC-AVX512或-march=knl)。
但您的 Coffee Lake 是主流台式机/笔记本电脑核心,必须快速运行任何过去或未来的二进制文件,包括仅使用“传统”SSE2 指令编码(而不是 AVX)的代码。
写入 XMM 寄存器的 SSE2 指令不会修改相应 YMM/ZMM 寄存器的高位元素。(XMM 寄存器是完整向量寄存器的低 128 位)。理论上,当在支持更宽向量的 CPU 上运行旧版 SSE2 指令时,这会产生错误的依赖关系。(像 Sandybridge 系列这样的主流 Intel CPU 通过模式转换来避免这种情况,或者如果使用不当,则在 Skylake 上实际的错误依赖关系上避免这种情况vzeroupper。请参阅为什么此 SSE 代码在 Skylake 上没有 VZEROUPPER 时会慢 6 倍?以比较这两种策略) 。
KNL显然有办法避免错误的依赖关系:根据 Agner Fog 的测试(在他的微体系结构指南中),他将其描述为 P6 系列在写入 AL 等整数寄存器时所做的部分寄存器重命名。当您读取完整寄存器时,您只会得到部分寄存器停顿。如果这是准确的,那么 SSE2 代码应该可以在 KNL 上正常运行,因为没有 AVX 代码读取 YMM 或 ZMM 寄存器。
(但是,如果存在错误的依赖关系,则movaps xmm0, [rdi]循环中的 a 可能必须等到上xmm0一次迭代中写入的最后一条指令完成为止。这将破坏 KNL 适度的无序执行能力,即跨循环迭代重叠独立工作并隐藏负载+ FP 延迟。)
运行旧版 SSE/SSE2 指令时,KNL 上的解码也有可能停止:它会在具有 3 个以上前缀(包括0F转义字节)的指令上停止。因此,例如任何带有 REX 前缀的 SSSE3 或 SSE4.x 指令访问 r8..r15 或 xmm8..xmm15 将导致解码停顿 5 到 6 个周期。
-x但如果省略所有/选项,则不会有这个-march,因为 SSE1/SSE2 + REX 仍然可以。只需(可选 REX)+ 2 个其他指令前缀,例如66 0F 58 addpd.
请参阅 KNL 章节中 Agner Fog 的微体系结构指南:16.2 指令获取和解码。
OpenMP - 如果您正在考虑 OpenMP 使用多线程,显然 KNL 有更多的内核。
但即使在一个物理内核中,KNL 也具有 4 路超线程作为另一种方式(除了乱序执行之外)来隐藏其 SIMD 指令的高延迟。例如,KNL 上的 FMA/add/sub 延迟为 6 个周期,而 Skylake/Coffee Lake 上为 4 个周期。
因此,将问题分解为多个线程有时可以显着提高 KNL 上每个核心的利用率。但在像 Coffee Lake 这样的主流大核 CPU 上,其大规模的乱序执行能力已经可以在许多循环中找到并利用所有指令级并行性,即使循环体对每个独立输入执行一系列操作。
| 归档时间: |
|
| 查看次数: |
1408 次 |
| 最近记录: |