繁体   English   中英

为什么矢量化通常比循环更快?

[英]Why is vectorization, faster in general, than loops?

为什么在硬件执行操作的最低级别和所涉及的一般底层操作(即:运行代码时所有编程语言的实际实现通用的东西),向量化通常比循环快得多?

计算机在循环时做什么而使用向量化时它不做(我说的是计算机执行的实际计算,而不是程序员编写的内容),或者它有什么不同?

我一直无法说服自己为什么差异会如此显着。 我可能会相信矢量化代码在某处减少了一些循环开销,但计算机仍然必须执行相同数量的操作,不是吗? 例如,如果我们将一个大小为 N 的向量乘以一个标量,我们将有 N 次乘法来执行任一方法,不是吗?

矢量化(作为通常使用的术语)是指 SIMD(单指令,多数据)操作。

这意味着,从本质上讲,一条指令并行地对多个操作数执行相同的操作。 例如,要将大小为 N 的向量乘以标量,我们将 M 称为它可以同时操作的大小的操作数的数量。 如果是这样,那么它需要执行的指令数量大约是 N/M,其中(纯标量操作)它必须执行 N 个操作。

例如,英特尔当前的 AVX 2 指令集使用 256 位寄存器。 这些可用于保存(和操作)一组 4 个 64 位的操作数,或 8 个 32 位的操作数。

因此,假设您正在处理 32 位单精度实数,这意味着一条指令可以一次执行 8 次运算(在您的情况下为乘法),因此(至少在理论上)您可以使用完成 N 次乘法只有 N/8 条乘法指令。 至少,理论上,这应该允许操作以一次执行一条指令所允许的大约 8 倍的速度完成。

当然,确切的好处取决于每条指令支持多少个操作数。 Intel 的第一次尝试仅支持 64 位寄存器,因此要同时操作 8 个项目,这些项目每个只能是 8 位。 他们目前支持 256 位寄存器,并且他们已经宣布支持 512 位(他们甚至可能已经在一些高端处理器中提供了这种支持,但至少在普通消费者处理器中没有提供)。 委婉地说,充分利用此功能也并非易事。 调度指令以便您实际上有 N 个操作数可用并且在正确的时间在正确的位置不一定是一项容易的任务(根本)。

从正确的角度来看,(现在古老的)Cray 1 正是通过这种方式获得了很多速度。 它的向量单元对每组 64 位的 64 个寄存器进行操作,因此每个时钟周期可以进行 64 次双精度运算。 在最佳矢量化代码中,它更接近当前 CPU 的速度,而不是仅基于其(低得多)时钟速度的预期。 充分利用这一点并不总是那么容易(现在仍然不是)。

但是请记住,矢量化并不是CPU 可以并行执行操作的唯一方式。 还有指令级并行的可能性,它允许单个 CPU(或 CPU 的单个内核)一次执行多条指令。 如果指令是加载、存储和 ALU 的混合,大多数现代 CPU 包括硬件(理论上)每个时钟周期1最多执行大约 4 条指令。 当内存不是瓶颈时,它们可以相当常规地平均每个时钟执行接近 2 条指令,或者在调整良好的循环中执行更多指令。

然后,当然,还有多线程——在(至少在逻辑上)独立的处理器/内核上运行多个指令流。

因此,现代 CPU 可能有 4 个内核,每个内核每个时钟可以执行 2 个向量乘法,并且每个指令都可以在 8 个操作数上运行。 因此,至少在理论上,它每个时钟可以执行 4 * 2 * 8 = 64 次操作。

一些指令有更好或更差的吞吐量。 例如,在 Skylake 之前的 Intel 上,FP 添加的吞吐量低于 FMA 或乘法(每个时钟 1 个向量而不是 2 个)。 但是像 AND 或 XOR 这样的布尔逻辑每个时钟吞吐量有 3 个向量; 构建 AND/XOR/OR 执行单元不需要很多晶体管,因此 CPU 会复制它们。 使用高吞吐量指令时,总流水线宽度(前端解码并发布到内核的乱序部分)上的瓶颈很常见,而不是特定执行单元上的瓶颈。


  1. 但是,随着时间的推移,CPU 往往会拥有更多可用资源,因此这个数字会上升。

矢量化有两个主要好处。

  1. 主要优点是设计用于支持向量指令的硬件通常具有在使用向量指令时能够并行执行多个 ALU 操作的硬件。 例如,如果您要求它使用 16 元素向量指令执行 16 次加法,则它可能有 16 个加法器可以同时并行执行所有加法。 访问所有这些加法器1唯一方法是通过矢量化。 使用标量指令,您只会得到 1 个孤独的加法器。

  2. 使用向量指令通常可以节省一些开销。 您以大块的形式加载和存储数据(在一些最近的 Intel CPU 上一次最多 512 位),并且每次循环迭代都会做更多的工作,因此相对而言循环开销通常较低2 ,并且您需要更少的指令来执行同样的工作,所以 CPU 前端开销更低,等等。

最后,循环矢量化之间的二分法很奇怪。 当您使用非矢量代码并将其矢量化时,如果之前有循环,您通常会以循环结束,如果没有,则不会结束。 比较实际上是在标量(非向量)指令和向量指令之间进行的。


1或至少 16 个中的 15 个,也许其中一个也用于进行标量运算。

2在标量情况下,您可能会以大量循环展开为代价获得类似的循环开销优势。

矢量化是一种并行处理。 它使更多的计算机硬件用于执行计算,因此计算速度更快。

许多数值问题,尤其是偏微分方程的求解,需要对大量单元、单元或节点进行相同的计算。 矢量化并行执行许多单元格/元素/节点的计算。

矢量化使用特殊硬件。 与多核 CPU 不同,每个并行处理单元都是一个功能齐全的 CPU 内核,向量处理单元只能执行简单的操作,所有单元同时执行相同的操作,对一系列数据值进行操作(向量)同时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM