降低 CPU 频率的 SIMD 指令
Posted
技术标签:
【中文标题】降低 CPU 频率的 SIMD 指令【英文标题】:SIMD instructions lowering CPU frequency 【发布时间】:2019-11-13 02:55:49 【问题描述】:我读到了这个article。它讲了为什么要使用 AVX-512 指令:
英特尔最新的处理器具有高级指令 (AVX-512),可能会导致内核或 CPU 的其余部分运行速度变慢,因为它们使用了多少功率。
我想在Agner's blog 上也提到过类似的东西(但我找不到确切的帖子)。
我想知道 Skylake 支持的其他指令有哪些类似的效果,它们会降低功率以最大化以后的吞吐量?所有 v 前缀指令(如vmovapd
、vmulpd
、vaddpd
、vsubpd
、vfmadd213pd
)?
我正在尝试编译一个指令列表,以便在为 Xeon Skylake 编译 C++ 应用程序时避免使用。
【问题讨论】:
Trevis Down(在 OS 上又名 Beeonrope)在 post 的 cmets 中写了这个,并继续讨论 here。他发现每个关系(标量、AVX/AVX2、AVX-512)都有“便宜”(没有 FP,简单操作)指令和“重”指令。即使很少使用,廉价指令也会将频率降低到下一个更高层(例如,廉价的 AVX-512 使用 AVX/AVX2 层)。重型 inst 必须使用超过 1 次... ... 两个周期并根据其等级降低频率(例如,AVX-512 重型仪器将频率降低到 AV-512 基础)。 Travis 还分享了他用来测试here 的代码。您可以通过耐心或根据他的经验法则找到每条指令的行为。最后请注意,如果矢量指令与标量指令的比率足够低,以至于频率下降无法通过处理数据的更大宽度来平衡,那么这种频率缩放是一个问题。检查最终的二进制文件,看看你是否真的有所收获。 @HCSF 您可以构建三个版本,一个不带 AVX,一个带 AVX/AVX2,一个带 AVX-512(如果适用)并配置它们。然后拿最快的。 Peter 提到了-mpreferred-vector-width=256
选项。我不知道它是否会阻止 gcc ever 生成 AVX-512 指令(在直接内部使用之外),但这当然是可能的。但是,我不知道任何区分“重”和“轻”指令的选项。通常这不是问题,因为如果您关闭 AVX-512 并且没有一堆 FP 操作,那么您可能无论如何都针对 L0,而 AVX-512 灯仍然是 L1。
@HCSF libc 中的重要例程通常针对不同的 ISA 编译多次,然后在运行时使用动态加载程序的 IFUNC 功能选择适合当前 CPU 的版本。所以你通常会得到一个针对你的 CPU 优化的版本(除非你的 libc 很旧而你的 CPU 很新)。
【参考方案1】:
重要的不是指令助记符,重要的是 512 位向量宽度根本。
您可以使用 256 位版本的 AVX-512VL 指令,例如vpternlogd ymm0, ymm1, ymm2
不会导致 AVX-512 涡轮增压损失。
相关:Dynamically determining where a rogue AVX-512 instruction is executing 是关于 glibc 初始化代码中的一条 AVX-512 指令或某些东西留下了一个肮脏的上 ZMM 的情况,该 ZMM 在剩余的进程生命周期中使最大涡轮增压。 (或者直到vzeroupper
可能)
尽管轻/重度使用 256 位 FP 数学指令可能会产生其他 turbo 影响,其中一些是由于热量造成的。但通常 256 位在现代 CPU 上是值得的。
无论如何,这就是为什么gcc -march=skylake-avx512
默认为-mprefer-vector-width=256
。对于任何给定的工作负载,都值得尝试-mprefer-vector-width=512
,也可能是 128,这取决于有多少工作可以有效地自动矢量化。
告诉 GCC 为您的 CPU 进行调整(例如 -march=native
),希望它会做出不错的选择。尽管在台式机 Skylake-X 上,涡轮增压损失比 Xeon 小。如果您的代码确实受益于 512 位矢量化,那么付出代价是值得的。
(还要注意 Skylake 系列 CPU 进入 512 位向量模式的另一个主要影响:端口 1 上的向量 ALU 关闭,因此只有像 popcnt
或 add
这样的标量指令可以使用端口 1。所以vpand
和 vpaddb
等。吞吐量从每时钟 3 下降到 2。如果您在具有两个 512 位 FMA 单元的 SKX 上,端口 5 上的额外一个会加电,因此 FMA 与洗牌竞争。 )
【讨论】:
我的二进制文件已经使用-march=generic
很长时间了。所以我认为即使-march=skylake-avx512 -mpreferred-vector-width=128
也会进行一些优化,而不会因使用 avx-256(如我所要求的 128)而受到严重惩罚。想过吗?
@HCSF:当然,skylake + width=128 应该比在 SKX 上运行的泛型更好。如果 GCC 使用 AVX512 EVEX 编码指令不必要地膨胀代码大小(例如,vmovdqu64 xmm
而不是 vmovdqu xmm
,当不使用 xmm16..31 时),并且通常比较成-mask 与比较向量和混合的 SSE/AVX 方式相比应该更好。 但您也绝对应该使用默认宽度 = 256 进行测试,以防涡轮惩罚对您的代码来说是值得的。 每个 uop 做两倍的工作非常好,而且大惩罚只会踢使用 512 位向量。
当我使用-march=skylake-avx512 -mprefer-vector-width=128
编译时,我实际上看到了您刚才提到的内容——vmovdqu64 (%rdx),%xmm0
、vmovdqu64 0x10(%rsi),%xmm6
等。似乎 GCC 8.2 做得不对(或者不是您的预期)?
@HCSF:是的,这是 GCC 中错过的优化,会损害代码大小,但除此之外不是问题。如果 GCC 没有从 AVX512 功能(如更多寄存器或掩码)或新指令(如 vpternlogd xmm
)中获得任何好处,那么请尝试 -mno-avx512f
以查看代码大小效应是否有所不同。但是大多数指令都有一个 SIMD 元素大小,因此 EVEX 版本没有单独的助记符来允许每个元素屏蔽。因此,汇编器可以将vpaddd %xmm
汇编到 VEX 版本,而 GCC 不能自找麻烦。 (使用 xmm16..31 除外)
试过 -march=skylake-avx512 -mprefer-vector-width=128 -mno-avx512f
甚至没有将我的二进制文件的大小改变 1 个字节(我使用 strip
命令先删除文本内容)【参考方案2】:
频率影响取决于指令的宽度和使用的指令。
共有三个频率级别,即所谓的许可证,从最快到最慢:L0、L1 和 L2。 L0 是您在包装盒上看到的“标称”速度:当芯片显示“3.5 GHz turbo”时,它们指的是单核 L0 turbo。 L1 是一种较低的速度,有时称为 AVX turbo 或 AVX2 turbo5,最初与 AVX 和 AVX2 指令相关1 . L2 的速度低于 L1,有时称为“AVX-512 turbo”。
每个许可证的确切速度还取决于活动内核的数量。对于最新的表格,您通常可以咨询WikiChip。例如,Xeon Gold 5120 的表是here:
Normal、AVX2 和 AVX512 行分别对应于 L0、L1 和 L2 许可证。请注意,随着内核数量的增加,L1 和 L2 许可证的相对减速通常会变得更糟:对于 1 或 2 个活动内核,L1 和 L2 速度是 L0 的 97% 和 91%,但对于 13 或 14 个内核,它们是 85%和 62%。这因芯片而异,但总体趋势通常是相同的。
先不做这些准备工作,让我们来看看我认为您要问的问题:哪些指令会导致激活哪些许可证?
这是一个表格,显示了基于宽度和分类为light或heavy的指令的隐含许可:
Width Light Heavy
--------- ------- -------
Scalar L0 N/A
128-bit L0 L0
256-bit L0 L1*
512-bit L1 L2*
*soft transition (see below)
因此我们立即看到所有标量(非 SIMD)指令和所有 128 位宽指令2始终在 L0 许可证中全速运行。
256 位指令将在 L0 或 L1 中运行,具体取决于它们是 light 还是 heavy,而 512 位指令将在 L1 或 L2 中运行相同的基础。
那么这个轻而重的东西是什么?
轻与重
从解释繁重的指令开始是最简单的。
Heavy指令都是需要在FP/FMA单元上运行的SIMD指令。基本上这是大部分的 FP 指令(通常以 ps
或 pd
结尾,如 addpd
)以及主要以 vpmul
或 vpmad
开头的 integer 乘法指令因为 SIMD 整数乘法实际上在 SIMD 单元上运行,vplzcnt(q|d)
显然也在 FMA 单元上运行。
鉴于此,简单的说明就是其他一切。特别是,除乘法、逻辑指令、混洗/混合(包括 FP)和 SIMD 加载和存储之外的整数算术是轻量级的。
过渡
Heavy 列中的 L1 和 L2 条目标有星号,例如 L1*
。这是因为这些指令在发生时会导致 软 转换。另一个 L1 条目(用于 512 位轻指令)导致硬转换。在这里,我们将讨论这两种转换类型。
硬过渡
只要具有给定许可证的任何指令执行,就会立即发生硬转换4。 CPU 停止,占用一些halt cycles 并进入新模式。
软过渡
与硬转换不同,软转换不会在任何指令执行后立即发生。相反,指令最初以降低的吞吐量执行(低至正常速率的 1/4),而不改变频率。如果 CPU 确定每单位时间正在执行“足够”繁重的指令,并且达到特定阈值,则会转换到更高编号的许可证。
也就是说,CPU 明白,如果只有少数重指令到达,或者即使有很多到达但在考虑其他非重指令时它们并不密集,则可能不值得减少频率。
指南
鉴于上述情况,我们可以建立一些合理的指导方针。您永远不必害怕 128 位指令,因为它们不会导致与许可证相关的3 降频。
此外,您也不必担心轻 256 位宽的指令,因为它们也不会导致降频。如果您不使用大量矢量化 FP 数学,则不太可能使用繁重的指令,因此这适用于您。事实上,当您使用适当的 -march
选项时,编译器已经大量插入 256 位指令,尤其是对于数据移动和自动矢量化循环。
使用繁重的 AVX/AVX2 指令和轻量的 AVX-512 指令比较棘手,因为您将在 L1 许可证中运行。如果只有一小部分流程(比如 10%)可以利用,那么减慢应用程序的其余部分可能不值得。与 L1 相关的处罚通常是中等的 - 但请查看您的筹码详情。
使用繁重的 AVX-512 指令更加棘手,因为 L2 许可证在大多数芯片上都会带来严重的频率损失。另一方面,重要的是要注意只有 FP 和整数乘法指令属于 heavy 类别,因此实际上很多整数 512 位宽的使用只会产生 L1 许可证.
1 虽然,正如我们将看到的,这有点用词不当,因为 AVX-512 指令可以设置此许可证的速度,而某些 AVX/2 指令则不能。
2 128 位宽意味着使用 xmm 寄存器,无论它们是在什么指令集中引入的 - 主流 AVX-512 包含适用于大多数/所有的 128 位变体新指令。
3 注意 weasel 条款 与许可证相关 - 您当然可能会遭受其他降频原因,例如热、功率或电流限制,并且可能是 128-位指令可能会触发这种情况,但我认为这在台式机或服务器系统上不太可能(低功耗、小型设备是另一回事)。
4 显然,我们只讨论到更高级别许可证的转换,例如,当硬转换 L1 指令执行时,从 L0 到 L1。如果您已经在 L1 或 L2 什么都不会发生 - 如果您已经在同一级别,并且您不会根据任何特定指令转换到较低编号的级别,而是在没有任何指令的情况下运行一段时间,则不会发生任何转换编号较高的级别。
5 在这两个 AVX2 turbo 中比较常见,我从来没有真正理解过,因为 256 位指令与 AVX 的相关性与 AVX2 一样多,并且大多数实际触发 AVX turbo(L1 许可证)的 重 指令实际上是 AVX 中的 FP 指令,而不是 AVX2。唯一的例外是 AVX2 整数乘法。
【讨论】:
评论不用于扩展讨论;这个对话是moved to chat。 有趣。不过,FMA 单元上的vplznctd/q
是有道理的:它需要位扫描硬件通过找到有效数结果的 MSB 来重新规范化 FP 数学的结果。
@PeterCordes - 是的,我看到了这个here,它链接了对所有 AVX-512 指令的综合测试。不过,正如该推文中的 cmets 所述,它有一些奇怪的地方:虽然 256 位版本显然“重”,但根据该测试,512 位版本似乎大多是轻量级的。但是,测试可能根本不会触发 L2,因为指令不够密集。
有趣的是,Twitter 帖子指出的转储似乎表明 所有 整数乘法实际上是“轻的”,除了 VPMULLD
- 我没看错吗?
@Zboson - 我认为它首先出现在 Haswell 服务器芯片中,即 Haswell-EP 或其他任何名称。 AVX2 turbo speed 这个名字对我来说从来没有多大意义:它主要影响来自 AVX 集合的 FP 指令,而不是主要是整数的 AVX2(整数 mul 是一个例外)。英特尔自己使用 AVX,而不是 early documents 中的 AVX2。人们似乎喜欢称它为 AVX2,也许是因为它出现在 Haswell 中,而 AVX2 是新的 ISA?以上是关于降低 CPU 频率的 SIMD 指令的主要内容,如果未能解决你的问题,请参考以下文章
SSE再学习:灵活运用SIMD指令16倍提升Sobel边缘检测的速度(4000*3000的24位图像时间由480ms降低到30ms)。
HPCIntel SIMD技术——如何用code检查你的CPU支持哪些指令集?