向量化是什么意思?

45

对于代码进行向量化是一个好的想法吗?在何时进行向量化方面有哪些良好的实践经验?底层会发生什么?


6
好的,我会尽力进行翻译。以下是需要翻译的内容:See also: https://dev59.com/nXM_5IYBdhLWcg3wUxjF请参见:https://dev59.com/nXM_5IYBdhLWcg3wUxjF - Stephen Canon
5个回答

65

向量化意味着编译器会检测到您的独立指令可以作为一个SIMD指令执行。通常的例子是,如果您执行以下操作:

for (i = 0; i < N; i++) {
    a[i] = a[i] + b[i];
}

使用向量符号,它将被矢量化为

for (i = 0; i < (N - N % VF); i += VF) {
    a[i : i + VF] = a[i : i + VF] + b[i : i + VF];
}

基本上,编译器会选择在同一时间对数组的VF元素执行一个可以完成的操作,并将其执行N/VF次,而不是执行单个操作N次。

这增加了性能,但对架构提出了更多要求。


8
除了打开优化选项,程序员还能做些什么来确保向量化呢? - Jacob
1
据我所知,编译器在自动向量化方面存在一定的限制,因此最好将代码保持尽可能简单。此外,您可以检查生成的汇编代码,以查看编译器是否进行了向量化处理。 - Zed
2
@jacob:你不能真正“确保”它,你可能需要查看http://openmp.org/,以了解显式告诉编译器进行向量化的方法。 - D.Shawley
7
向量化并不意味着由编译器完成,只是使用了SIMD指令。当编译器生成SIMD代码时,通常被称为自动向量化。 - jalf

17

如上所述,向量化被用于利用SIMD指令,这些指令可以对不同数据打包到大型寄存器中的相同操作进行操作。

使编译器能够自动向量化循环的一般准则是确保不会在不同迭代的循环中存在数据元素之间的流和反依赖性。

http://zh.wikipedia.org/wiki/数据依赖

像英特尔C++/Fortran编译器等一些编译器能够自动向量化代码。如果它无法向量化一个循环,英特尔编译器能够报告为什么不能这样做。这些报告可以用来修改代码,使其变得可向量化(假设可能)

依赖关系在书籍“Optimizing Compilers for Modern Architectures: A Dependence-based Approach”中有详细讲解。


3
矢量化不一定局限于只能使用一个可以容纳大量数据的寄存器。例如,使用“128”位寄存器来容纳“4 x 32”位数据。这取决于架构限制。有些架构有不同的执行单元,它们具有自己的寄存器。在这种情况下,部分数据可以被馈送到该执行单元,并且结果可以从相应的执行单元寄存器中获取。
例如,考虑以下情况。
for(i=0; i < N; i++) { a[i] = a[i] + b[i]; }
如果我正在使用具有两个执行单元的架构,则我的矢量大小定义为2。上述循环将被重新构建为
for(i=0; i<(N/2); i+=2) { a[i] = a[i] + b[i];
a[i+1] = a[i+1] + b[i+1]; } 注意:for语句内部的2是由矢量大小推导出来的。
由于我有两个执行单元,因此循环内的两个语句将被馈入两个执行单元中。求和将分别在执行单元中累积。最后将执行单元中累积值的总和进行操作。
良好的实践包括:
1. 在对循环进行矢量化之前,需要检查依赖性(在循环的不同迭代之间)等限制。
2. 需要防止函数调用。
3. 指针访问可能会创建别名,并且需要加以防止。

2

这是SSE代码生成。

您有一个循环,其中包含浮点矩阵代码matrix1[i][j] + matrix2[i][j],编译器会生成SSE代码。


2
SEE 不是唯一的矢量指令集。PPC 有 Altivec,其他架构也有自己的矢量指令。 - Amok

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接