为什么矢量化一般比循环更快?

时间:2016-01-29 18:55:15

标签: performance language-agnostic vectorization low-level

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

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

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

3 个答案:

答案 0 :(得分:35)

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

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

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

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

当然,确切的好处取决于每条指令支持的操作数。英特尔的首次尝试仅支持64位寄存器,因此要同时操作8个项目,这些项目每个只能是8位。他们目前支持256位寄存器,并且他们已经宣布支持512位(他们甚至可能在一些高端处理器中出货,但至少在普通的消费者处理器中没有)。说得好一点,充分利用这种能力也是非常重要的。调度指令使你实际上有N个操作数可用并且在正确的时间在正确的位置并不是一件容易的事(根本不是)。

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

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

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

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

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

答案 1 :(得分:2)

矢量化有两个主要好处。

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

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

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

    1 或者16个中至少有15个,也许一个也用于标量操作。

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

答案 2 :(得分:1)

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

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

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