AVX/AVX2 "exists" 在每个核心上吗?
Does AVX/AVX2 "exists" on each core?
所以,这个 AVX 东西 - 它就像每个内核的小机器?或者它就像一个引擎单元整个 CPU?
比如,我能以某种方式在每个内核上使用它吗?我正在玩它,我觉得我可能会“过度使用”它并造成某种瓶颈。
你能解释一下吗?我是不是都听错了?
高级矢量扩展(AVX)是指令。每个 CPU 都有不同的硬件来实现它们。据我所知,每个内核都有自己的硬件,用于与这些指令(以及其他指令)相关的所有内容,因此它们之间没有交互。
内存也将完全隔离,因为每个内核都将在自己的 L1 和 L2 缓存上工作。第一次交互将发生在 L3 缓存上,这意味着在并行化(多线程软件)之后,您应该获得性能提升,除非您从一个处理器访问内存的方式开始与另一个处理器的访问冲突。
但我的感觉是,你担心的太多了。
它可以通过几种不同的方式实现。在大多数现代 CPU 中,每个内核都有 256 位 AVX 实现。
关于它是如何完成的,有很多繁琐的细节。有些人可能会执行两次 128 位进程。其他人在一个周期内完成,但会降低核心频率。在所有情况下,它都会增加核心功率使用和热量输出,仅仅是因为它做了更多的工作。 运行 超线程对上的两个 AVX 处理线程可能 运行 速度减半,因为它们无法共享 AVX 单元。等等
如果您正在编写速度和延迟非常重要的游戏之类的东西,那么最好的办法是对其进行测量。要么在您的实验室中对许多不同类型的硬件进行基准测试,要么在游戏开始时进行快速基准测试,然后在配置中设置默认值。
也可能存在内存瓶颈。我不久前设法写了一些 AVX 代码(只是为了我自己的乐趣),这些代码达到了笔记本电脑上的 CPU 内存带宽限制。不过在 Xeon 上 运行ning 没有问题。
现代 CPUs 上的 SIMD 指令,如 AVX vmulps ymm1, ymm2, ymm3
or SSE2 pmaddwd xmm0, xmm1
,完全在物理内核中执行 运行ning 该指令。 每个物理内核都有自己的执行资源,包括 SIMD/FP 个执行单元。(在 CPU 架构中,标量 FP 通常与 SIMD 组合在一起。在现代 x86 中,您实际上在向量寄存器的低位元素上使用 SSE2 或 AVX 指令的标量版本来进行标量 FP 数学运算。)
这就是为什么最大 FLOP/s 随内核数量扩展的原因:FLOPS per cycle for sandy-bridge and haswell SSE2/AVX/AVX2
(甚至每个内核也不只有一个“AVX 单元”,例如 Haswell 和 Zen2 内核都有两个 256 位宽的 FMA 单元,并且可以在更多端口上 运行 按位布尔向量指令以获得更高的 per-clock 这些指令的吞吐量。)
CPUs 处理 SIMD 指令(几乎)与 add eax, ecx
等整数指令完全一样。这(除其他原因外)就是为什么 x86 CPUs 可以有效地在整数和 FP 寄存器之间获取数据且延迟非常低,对于 cvttss2si eax, xmm0
(float->int with t运行cation)或vpmovmskb eax, ymm0
(每个字节高位的位图)。 https://uops.info/ and https://agner.org/optimize/ 有更多关于性能数据的详细信息。
有关 Intel Haswell 中每个执行端口上的执行单元的图表,请参阅 https://www.realworldtech.com/haswell-cpu/4/。请注意,标量整数乘法器 (imul
) 与 vaddps
在同一端口上,因此这些指令不能同时在给定内核的同一时钟周期内开始执行。 (Skylake 运行s vaddps 在其 2 个 FMA 单元中的任何一个上)。
有关 CPU 工作原理的更多背景信息,请参阅 现代微处理器
90 分钟指南!.
AMD Bulldozer-family,成对的内核共享一个 SIMD/FP 单元(和缓存)
在Bulldozer/Piledriver/Steamroller/Excavator中,每个对(weak-ish)个整数核心共享一个SIMD/FP单元、L1i缓存和L2缓存。这基本上是 SMT(例如 Intel 的超线程)的替代方案,它在所有内核都忙的情况下具有更多的总吞吐量,但没有能力 运行 单个线程与单个更宽的线程一样快核心.
因此,考虑到它们的紧密耦合,这并不是通常意义上的两个独立核心。但它也不是可以 运行 两个硬件线程的单个内核。这就像连体双胞胎分享他们的一部分 body。 https://www.realworldtech.com/bulldozer/2/ 描述得更详细了。
Bulldozer-family 代表了在 CPU 架构中的一些实验,其中许多被证明是不成功的。 (就像一个 write-through L1d 缓存和一个小的 4k write-combining 缓冲区)。 AMD Zen 使用了一种更传统的设计,与英特尔的非常相似:使用 SMT 完全分离宽内核,以实现高 single-thread 性能和 运行 具有良好总吞吐量的大量线程。以及具有普通 write-back L1d 缓存的更常规的缓存层次结构。 Zen 保留了 AMD 对 SIMD/FP 与 scalar-integer 管道部分的分离,这与英特尔更统一的调度程序和执行端口不同。 Zen1 甚至保留了 AMD 一贯的将 256 位指令拆分为 2 微指令的技术,直到 Zen 2 扩大了执行单元。 (英特尔已经在早期的 CPU 上为 SSE 完成了这种拆分,例如 Pentium III 和 Pentium-M,但自 Core 2 以来还没有这样做:full-width 它们支持的任何 SIMD 扩展的执行单元。 )
Bulldozer 上的 SIMD / FP 指令具有更高的延迟(即使像 pxor xmm0,xmm1
这样的东西也至少有 2 个周期)但这可能是由于 Bulldozer 的“速度恶魔”方法提高了时钟频率。在整数和 FP 寄存器之间获取数据的延迟特别糟糕,比如 10 个周期。 (但通常你不会一直来回传输数据,并且在 FP 负载的寻址模式中使用整数 regs 很好。这不是 Bulldozer-family CPUs 相对的主要原因或唯一原因慢。)
所以它 不像 rdrand eax
那样 rdrand eax
必须从所有内核共享的随机源中提取数据,并且与普通指令(如 200 个周期)相比非常慢在 Ivy Bridge 上,更像是一个 cache-miss 负载)因为它必须去 off-core。而且因为它的使用频率不够高,不足以证明构建更多硬件以使其更快(例如,在每个内核中缓冲随机性)是合理的。 (What is the latency and throughput of the RDRAND instruction on Ivy Bridge? 有在英特尔工作的 David Johnston 的回答)。
所以,这个 AVX 东西 - 它就像每个内核的小机器?或者它就像一个引擎单元整个 CPU?
比如,我能以某种方式在每个内核上使用它吗?我正在玩它,我觉得我可能会“过度使用”它并造成某种瓶颈。
你能解释一下吗?我是不是都听错了?
高级矢量扩展(AVX)是指令。每个 CPU 都有不同的硬件来实现它们。据我所知,每个内核都有自己的硬件,用于与这些指令(以及其他指令)相关的所有内容,因此它们之间没有交互。
内存也将完全隔离,因为每个内核都将在自己的 L1 和 L2 缓存上工作。第一次交互将发生在 L3 缓存上,这意味着在并行化(多线程软件)之后,您应该获得性能提升,除非您从一个处理器访问内存的方式开始与另一个处理器的访问冲突。
但我的感觉是,你担心的太多了。
它可以通过几种不同的方式实现。在大多数现代 CPU 中,每个内核都有 256 位 AVX 实现。
关于它是如何完成的,有很多繁琐的细节。有些人可能会执行两次 128 位进程。其他人在一个周期内完成,但会降低核心频率。在所有情况下,它都会增加核心功率使用和热量输出,仅仅是因为它做了更多的工作。 运行 超线程对上的两个 AVX 处理线程可能 运行 速度减半,因为它们无法共享 AVX 单元。等等
如果您正在编写速度和延迟非常重要的游戏之类的东西,那么最好的办法是对其进行测量。要么在您的实验室中对许多不同类型的硬件进行基准测试,要么在游戏开始时进行快速基准测试,然后在配置中设置默认值。
也可能存在内存瓶颈。我不久前设法写了一些 AVX 代码(只是为了我自己的乐趣),这些代码达到了笔记本电脑上的 CPU 内存带宽限制。不过在 Xeon 上 运行ning 没有问题。
现代 CPUs 上的 SIMD 指令,如 AVX vmulps ymm1, ymm2, ymm3
or SSE2 pmaddwd xmm0, xmm1
,完全在物理内核中执行 运行ning 该指令。 每个物理内核都有自己的执行资源,包括 SIMD/FP 个执行单元。(在 CPU 架构中,标量 FP 通常与 SIMD 组合在一起。在现代 x86 中,您实际上在向量寄存器的低位元素上使用 SSE2 或 AVX 指令的标量版本来进行标量 FP 数学运算。)
这就是为什么最大 FLOP/s 随内核数量扩展的原因:FLOPS per cycle for sandy-bridge and haswell SSE2/AVX/AVX2
(甚至每个内核也不只有一个“AVX 单元”,例如 Haswell 和 Zen2 内核都有两个 256 位宽的 FMA 单元,并且可以在更多端口上 运行 按位布尔向量指令以获得更高的 per-clock 这些指令的吞吐量。)
CPUs 处理 SIMD 指令(几乎)与 add eax, ecx
等整数指令完全一样。这(除其他原因外)就是为什么 x86 CPUs 可以有效地在整数和 FP 寄存器之间获取数据且延迟非常低,对于 cvttss2si eax, xmm0
(float->int with t运行cation)或vpmovmskb eax, ymm0
(每个字节高位的位图)。 https://uops.info/ and https://agner.org/optimize/ 有更多关于性能数据的详细信息。
有关 Intel Haswell 中每个执行端口上的执行单元的图表,请参阅 https://www.realworldtech.com/haswell-cpu/4/。请注意,标量整数乘法器 (imul
) 与 vaddps
在同一端口上,因此这些指令不能同时在给定内核的同一时钟周期内开始执行。 (Skylake 运行s vaddps 在其 2 个 FMA 单元中的任何一个上)。
有关 CPU 工作原理的更多背景信息,请参阅 现代微处理器 90 分钟指南!.
AMD Bulldozer-family,成对的内核共享一个 SIMD/FP 单元(和缓存)
在Bulldozer/Piledriver/Steamroller/Excavator中,每个对(weak-ish)个整数核心共享一个SIMD/FP单元、L1i缓存和L2缓存。这基本上是 SMT(例如 Intel 的超线程)的替代方案,它在所有内核都忙的情况下具有更多的总吞吐量,但没有能力 运行 单个线程与单个更宽的线程一样快核心.
因此,考虑到它们的紧密耦合,这并不是通常意义上的两个独立核心。但它也不是可以 运行 两个硬件线程的单个内核。这就像连体双胞胎分享他们的一部分 body。 https://www.realworldtech.com/bulldozer/2/ 描述得更详细了。
Bulldozer-family 代表了在 CPU 架构中的一些实验,其中许多被证明是不成功的。 (就像一个 write-through L1d 缓存和一个小的 4k write-combining 缓冲区)。 AMD Zen 使用了一种更传统的设计,与英特尔的非常相似:使用 SMT 完全分离宽内核,以实现高 single-thread 性能和 运行 具有良好总吞吐量的大量线程。以及具有普通 write-back L1d 缓存的更常规的缓存层次结构。 Zen 保留了 AMD 对 SIMD/FP 与 scalar-integer 管道部分的分离,这与英特尔更统一的调度程序和执行端口不同。 Zen1 甚至保留了 AMD 一贯的将 256 位指令拆分为 2 微指令的技术,直到 Zen 2 扩大了执行单元。 (英特尔已经在早期的 CPU 上为 SSE 完成了这种拆分,例如 Pentium III 和 Pentium-M,但自 Core 2 以来还没有这样做:full-width 它们支持的任何 SIMD 扩展的执行单元。 )
Bulldozer 上的 SIMD / FP 指令具有更高的延迟(即使像 pxor xmm0,xmm1
这样的东西也至少有 2 个周期)但这可能是由于 Bulldozer 的“速度恶魔”方法提高了时钟频率。在整数和 FP 寄存器之间获取数据的延迟特别糟糕,比如 10 个周期。 (但通常你不会一直来回传输数据,并且在 FP 负载的寻址模式中使用整数 regs 很好。这不是 Bulldozer-family CPUs 相对的主要原因或唯一原因慢。)
所以它 不像 rdrand eax
那样 rdrand eax
必须从所有内核共享的随机源中提取数据,并且与普通指令(如 200 个周期)相比非常慢在 Ivy Bridge 上,更像是一个 cache-miss 负载)因为它必须去 off-core。而且因为它的使用频率不够高,不足以证明构建更多硬件以使其更快(例如,在每个内核中缓冲随机性)是合理的。 (What is the latency and throughput of the RDRAND instruction on Ivy Bridge? 有在英特尔工作的 David Johnston 的回答)。