对代码进行矢量化是个好主意吗?在什么时候这样做有什么好的做法?下面会发生什么?
答案 0 :(得分:41)
向量化意味着编译器检测到您的独立指令可以作为一条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次。
它提高了性能,但对架构提出了更多要求。
答案 1 :(得分:12)
如上所述,矢量化用于利用SIMD指令,SIMD指令可以对填充到大寄存器中的不同数据执行相同的操作。
使编译器能够自动向量化循环的通用准则是确保在循环的不同迭代中没有流和反依赖性的b / w数据元素。
http://en.wikipedia.org/wiki/Data_dependency
某些编译器(如英特尔C ++ / Fortran编译器)能够自动生成代码。如果无法对循环进行矢量化,英特尔编译器就能够报告为什么它不能这样做。可以使用报告来修改代码,使其变得可矢量化(假设可能)
“为现代架构优化编译器:基于依赖的方法”一书中深入介绍了依赖关系
答案 2 :(得分:3)
这是SSE代码生成。
你有一个带有浮点矩阵代码的循环:matrix1 [i] [j] + matrix2 [i] [j],编译器生成SSE代码。
答案 3 :(得分:3)
矢量化不必限于可以容纳大数据的单个寄存器。就像使用'128'位寄存器来保存'4 x 32'位数据一样。这取决于架构限制。某些体系结构具有不同的执行单元,这些执在这种情况下,可以将一部分数据馈送到该执行单元,并且可以从对应于该执行单元的寄存器中获取结果。
例如,请考虑以下情况。
表示(i = 0; i
{
a [i] = a [i] + b [i];
}
如果我正在开发一个有两个执行单元的架构,那么我的矢量大小定义为两个。上面提到的循环将重新定义为
表示(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.指针访问可以创建别名,需要加以防止。
答案 4 :(得分:0)