矢量化(通常使用该术语)是指 SIMD(单指令、多数据)操作。
从本质上讲,这意味着一条指令对多个操作数并行执行相同的操作。例如,要将大小为 N 的向量乘以标量,我们将 M 称为它可以同时操作的大小的操作数的数量。如果是这样,那么它需要执行的指令数量大约为 N/M,其中(使用纯标量操作)它必须执行 N 个操作。
例如,Intel当前的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 的速度。充分利用这一点并不总是那么容易(而且仍然不是)。
Keep in mind, however, that vectorization is not the only way in which a CPU can carry out operations in parallel. There's also the possibility of instruction-level parallelism, which allows a single CPU (or the single core of a CPU) to execute more than one instruction at a time. Most modern CPUs include hardware to (theoretically) execute up to around 4 instructions per clock cycle1 if the instructions are a mix of loads, stores, and ALU. They can fairly routinely execute close to 2 instructions per clock on average, or more in well-tuned loops when memory isn't a bottleneck.
当然,还有多线程——在(至少逻辑上)单独的处理器/内核上运行多个指令流。
因此,现代 CPU 可能有 4 个内核,每个内核每个时钟可以执行 2 个向量乘法,并且每个指令可以对 8 个操作数进行操作。因此,至少在理论上,每个时钟可以执行 4 * 2 * 8 = 64 次操作。
有些指令具有更好或更差的吞吐量。例如,FP 增加的吞吐量低于 FMA,或者在 Skylake 之前在 Intel 上倍增(每个时钟 1 个向量,而不是 2 个向量)。但是像 AND 或 XOR 这样的布尔逻辑每个时钟吞吐量有 3 个向量;构建 AND/XOR/OR 执行单元并不需要很多晶体管,因此 CPU 会复制它们。使用高吞吐量指令时,总管道宽度(解码并发出到核心无序部分的前端)上的瓶颈很常见,而不是特定执行单元上的瓶颈。
- 但是,随着时间的推移,CPU 往往会拥有更多可用资源,因此这个数字会上升。