AVX/AVX2 是不是“存在”在每个内核上?

Posted

技术标签:

【中文标题】AVX/AVX2 是不是“存在”在每个内核上?【英文标题】:Does AVX/AVX2 "exists" on each core?AVX/AVX2 是否“存在”在每个内核上? 【发布时间】:2021-02-20 18:25:24 【问题描述】:

那么,这个 AVX 东西 - 它就像每个内核的小型机器?或者它就像一个引擎单元用于整个 CPU?

例如,我可以在每个核心上以某种方式使用它吗?我正在玩它,我觉得我可能会“过度使用”它并造成某种瓶颈。

你能解释一下吗?难道我都搞错了吗?

【问题讨论】:

AVX 是一个 ISA 扩展。原则上,这仅保证程序可以使用扩展中指定的状态和行为来执行数据处理,而不是 CPU如何处理实现此状态和行为。过去有多种方法可以虚拟化实现 CPU 功能所需的硬件。也就是说,在当前支持 AVX 的 Intel CPU 上,不同的物理内核不共享 AVX 资源(逻辑内核/超线程共享,但这与其他 CPU 资源没有什么不同)。 【参考方案1】:

现代 CPU 上的 SIMD 指令(如 AVX vmulps ymm1, ymm2, ymm3 或 SSE2 pmaddwd xmm0, xmm1)纯粹在运行该指令的物理内核中执行。 每个物理内核都有自己的执行资源,包括 SIMD/FP 执行单元。(在 CPU 架构中,标量 FP 通常与 SIMD 组合在一起。在现代 x86 中,您实际上使用的是 SSE2 或 AVX 指令的标量版本在向量寄存器的低元素上做标量 FP 数学。)

这就是为什么 max FLOP/s 会随着内核数量的增加而变化:FLOPS per cycle for sandy-bridge and haswell SSE2/AVX/AVX2

(即使每个内核也不仅仅是一个“AVX 单元”,例如 Haswell 和 Zen2 内核都具有两个 256 位宽的 FMA 单元,并且可以在更多端口上运行按位布尔向量指令以实现更高的每时钟这些指令的吞吐量。)

CPU 处理 SIMD 指令(几乎)与处理整数指令(例如 add eax, ecx)完全一样。这(以及其他原因)是 x86 CPU 可以在整数和 FP 寄存器之间以相当低的延迟有效获取数据的原因,对于像 cvttss2si eax, xmm0(float->int with truncation)或 vpmovmskb eax, ymm0(每个字节的高位的位图)。 https://uops.info/ 和 https://agner.org/optimize/ 有更多关于性能数据的详细信息。

有关英特尔 Haswell 中每个执行端口上的执行单元的图表,请参阅 https://www.realworldtech.com/haswell-cpu/4/。请注意,标量整数乘法器 (imul) 与 vaddps 在同一端口上,因此这些指令不能在给定内核上的相同时钟周期内开始执行。 (Skylake 在其 2 个 FMA 单元中的任何一个上运行 vaddps)。

有关 CPU 工作原理的更多背景信息,请参阅Modern Microprocessors A 90-Minute Guide!。


AMD Bulldozer 系列,内核对共享一个 SIMD/FP 单元(和缓存)

在 Bulldozer/Piledriver/Steamroller/Excavator 中,每 (弱)整数内核共享一个 SIMD/FP 单元、L1i 缓存和 L2 缓存。这基本上是SMT 的替代方案(例如英特尔的超线程),它在所有内核繁忙的情况下具有更高的总吞吐量,但无法像单个更宽的内核那样快速运行单个线程。

因此,考虑到它们的紧密耦合程度,这并不是通常意义上的两个独立内核。但它也不是一个可以运行两个硬件线程的内核。这就像连体双胞胎共享身体的一部分。 https://www.realworldtech.com/bulldozer/2/ 更详细地描述了它。

Bulldozer 系列代表了 CPU 架构中的许多实验,其中许多实验被证明是不成功的。 (就像具有小型 4k 写入组合缓冲区的直写 L1d 缓存)。 AMD Zen 使用了一种更传统的设计,很像英特尔的:完全分离的宽核和 SMT,以实现高单线程性能和运行大量线程并具有良好的聚合吞吐量。以及具有普通回写式 L1d 缓存的更传统的缓存层次结构。 Zen 保持 AMD 的 SIMD/FP 与管道的标量整数部分的分离,这与英特尔更统一的调度程序和执行端口不同。 Zen1 甚至保留了 AMD 将 256 位指令拆分为 2 个微指令的惯用技术,直到 Zen 2 扩大了执行单元。 (英特尔已经在 Pentium III 和 Pentium-M 等早期 CPU 上对 SSE 进行了这种拆分,但自 Core 2 以来就没有这样做过:它们支持的任何 SIMD 扩展的全宽执行单元。)

Bulldozer 上的 SIMD / FP 指令具有更高的延迟(即使对于 pxor xmm0,xmm1 之类的东西,最少也需要 2 个周期),但这可能是由于 Bulldozer 的“速度恶魔”方法导致的时钟更高。在整数和 FP 寄存器之间获取数据的延迟尤其糟糕,比如 10 个周期。 (但通常您不会一直来回弹跳数据,并且在寻址模式中使用整数 reg 来进行 FP 加载很好。这不是 Bulldozer 系列 CPU 相对较慢的主要原因或唯一原因。)


所以它rdrand eax 必须从所有内核共享的随机源中提取数据,并且与普通指令相比非常慢(如 Ivy Bridge 上的 200 个周期,更像是缓存未命中负载),因为它必须脱离核心。而且因为它的使用频率不足以证明构建更多硬件以使其更快(例如缓冲每个内核中的随机性)是合理的。 (What is the latency and throughput of the RDRAND instruction on Ivy Bridge? 得到了来自英特尔的 David Johnston 的回答)。

【讨论】:

【参考方案2】:

它可以通过几种不同的方式实现。在大多数现代 CPU 上,它们的每个内核都有 256 位 AVX 实现。

关于它是如何完成的有很多繁琐的细节。有些人可能会执行两次 128 位进程。其他人在一个周期内完成,但会减慢核心频率。在所有情况下,它都会增加核心功率使用和热量输出,因为它正在做更多的工作。在超线程对上运行两个 AVX 处理线程可能会以一半的速度运行,因为它们不能共享 AVX 单元。等等。

如果您正在编写游戏之类的游戏,其中速度和延迟非常重要,那么您最好的办法就是对其进行衡量。在您的实验室中对许多不同类型的硬件进行基准测试,或者在游戏开始时进行快速基准测试,然后在配置中设置默认值。

也可能存在内存瓶颈。不久前,我设法编写了一些 AVX 代码(只是为了我自己的乐趣),这些代码达到了笔记本电脑的 CPU 内存带宽限制。不过在 Xeon 上运行没有问题。

【讨论】:

在超线程对上运行两个 AVX 处理线程可能会以一半的速度运行,因为它们不能共享 AVX 单元。 - 这并不比整数代码更有可能,除了如果调整得当,AVX 循环往往没有分支,更有可能是相当高的吞吐量。但是,例如,如果它们在 FP 延迟方面遇到瓶颈,那么超线程可以提供很好的帮助。 “AVX 单元”实际上是不同执行端口上的多个执行单元,所有这些执行单元都是完全流水线的(除法器除外),因此两个线程在同一个物理内核上每个时钟可以平均每个时钟 1 个 FMA。 @PeterCordes 我的印象是大型寄存器的数量有限,这与 CPU 可以重命名多组 64 位寄存器的方式不同。上次我对这些东西进行大量基准测试是使用 Haswell CPU,可能有多种原因导致同一内核上的两个线程运行缓慢...... @ZanLynx:整数和 SIMD 有单独的物理寄存器文件,是的。但是在 Haswell 上,它们实际上是相同的大小,每个 168 个条目。 realworldtech.com/haswell-cpu/3。 (这比 ROB 大小略小,是的,可能是乱序执行窗口大小的限制因素。blog.stuffedcow.net/2013/05/measuring-rob-capacity)。但是,更多的 int phys regs 很常见,例如Skylake (180 int / 168 fp) 和 Zen1(168 int / 160 fp,但 YMM 寄存器采用 2 FP PRF 条目)。 有趣的事实:低功耗 Silvermont 只对整数执行 OoO 执行,而不是 FP 指令。 Silvermont 上的 FP/SIMD 没有注册重命名。但任何有自尊心的主流核心都会这样做;在循环迭代中找到 ILP 对于大多数 FP 循环来说非常很重要。【参考方案3】:

高级矢量扩展 (AVX) 是指令。每个 CPU 都有不同的硬件来实现它们。据我所知,每个内核都有自己的硬件,用于与这些指令相关的所有内容(以及其他指令),因此它们之间没有交互。

此外,内存将是完全隔离的,因为每个内核都将在其自己的 L1 和 L2 缓存上工作。第一次交互将发生在 L3 缓存上,这意味着在并行化(多线程软件)之后,您应该会获得性能提升,除非您从一个处理器访问内存的方式开始与另一个处理器的访问发生冲突。

但我的感觉是,你在需要之前就担心了很多。

【讨论】:

AVX 添加的不仅仅是指令,它加倍向量寄存器的大小,添加了很多状态。 AMD 和 Intel 的早期实现通常将至少一些 AVX 指令分成两半并在不同的周期中执行它们,以减少执行指令的功能单元的大小。 CPU 架构在过去(AMD Bulldozer,一些 MIPS)之间也共享向量单元状态,更不用说 SMT/超线程了。 @EOF:英特尔从未将 AVX 指令分成两半,除了 Sandybridge / Ivy Bridge 中的加载/存储端口只有 16 字节宽(即使在那时,它只是一个单一的 uop '没有完全流水线,需要一个额外的周期)。 SIMD ALU 在英特尔上一直是全宽的。 (除了 FP div/sqrt 单元,它实际上确实在 Skylake 之前为 vdivps ymm 占用了多个微指令。)

以上是关于AVX/AVX2 是不是“存在”在每个内核上?的主要内容,如果未能解决你的问题,请参考以下文章

MSVC /arch:[指令集] - SSE3、AVX、AVX2

如何使用 Ubuntu 20.04 64 位在 VirtualBox 6.1.16 中启用 AVX / AVX2?

在没有AVX的情况下编译boost

在没有 AVX 的情况下编译 boost

not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

您的 CPU 支持未编译此 TensorFlow 二进制文件以使用的指令:AVX AVX2