我试图对包含在数学库中使用'pow'函数的循环进行矢量化。我知道英特尔编译器支持使用'pow'作为sse指令 - 但我似乎无法使用gcc运行(我认为)。这就是我正在使用的情况:
int main(){
int i=0;
float a[256],
b[256];
float x= 2.3;
for (i =0 ; i<256; i++){
a[i]=1.5;
}
for (i=0; i<256; i++){
b[i]=pow(a[i],x);
}
for (i=0; i<256; i++){
b[i]=a[i]*a[i];
}
return 0;
}
我正在编译以下内容:
gcc -O3 -Wall -ftree-vectorize -msse2 -ftree-vectorizer-verbose=5 code.c -o runthis
这是在使用gcc版本4.2的os X 10.5.8上(我也使用了4.5,并且无法判断它是否有任何向量化 - 因为它根本没有输出任何内容)。似乎没有任何循环矢量化 - 是否存在一个对齐问题或者我需要使用限制的其他问题?如果我将其中一个循环写为函数,我会得到更详细的输出(代码):
void pow2(float *a, float * b, int n) {
int i;
for (i=0; i<n; i++){
b[i]=a[i]*a[i];
}
}
输出(使用7级详细输出):
note: not vectorized: can't determine dependence between *D.2878_13 and *D.2877_8
bad data dependence.
我查看了gcc auto-vectorization页面,但这并没有多大帮助。如果不能在gcc版本中使用pow,我在哪里可以找到执行pow等效函数的资源(我主要处理整数幂)。
编辑所以我只是深入研究其他来源 - 它是如何对此进行矢量化的?!:
void array_op(double * d,int len,double value,void (*f)(double*,double*) ) {
for ( int i = 0; i < len; i++ ){
f(&d[i],&value);
}
};
相关的gcc输出:
note: Profitability threshold is 3 loop iterations.
note: LOOP VECTORIZED.
那么现在我很茫然 - 'd'和'价值'被gcc不知道的函数修改 - 奇怪?也许我需要更彻底地测试这个部分,以确保矢量化部分的结果是正确的。还在寻找一个矢量化的数学库 - 为什么没有任何开源的数学库?
答案 0 :(得分:5)
在写输出之前使用__restrict
或消耗输入(分配到本地变量)应该会有所帮助。
就像现在一样,编译器无法进行向量化,因为a
可能是别名b
,因此并行4次并且写回4个值可能不正确。
(注意__restrict
不能保证编译器的矢量化,但现在可以这么说,确定不能)。
答案 1 :(得分:5)
这不是你问题的真正答案;而是建议如何完全避免这个问题。
你提到你在OS X上;该平台上已有API提供您正在查看的操作,无需自动向量化。你有没有理由不使用它们?自动矢量化真的很酷,但它需要一些工作,而且通常它不会产生与使用已经为你矢量化的API一样好的结果。
#include <string.h>
#include <Accelerate/Accelerate.h>
int main() {
int n = 256;
float a[256],
b[256];
// You can initialize the elements of a vector to a set value using memset_pattern:
float threehalves = 1.5f;
memset_pattern4(a, &threehalves, 4*n);
// Since you have a fixed exponent for all of the base values, we will use
// the vImage gamma functions. If you wanted to have different exponents
// for each input (i.e. from an array of exponents), you would use the vForce
// vvpowf( ) function instead (also part of Accelerate).
//
// If you don't need full accuracy, replace kvImageGamma_UseGammaValue with
// kvImageGamma_UseGammaValue_half_precision to get better performance.
GammaFunction func = vImageCreateGammaFunction(2.3f, kvImageGamma_UseGammaValue, 0);
vImage_Buffer src = { .data = a, .height = 1, .width = n, .rowBytes = 4*n };
vImage_Buffer dst = { .data = b, .height = 1, .width = n, .rowBytes = 4*n };
vImageGamma_PlanarF(&src, &dst, func, 0);
vImageDestroyGammaFunction(func);
// To simply square a instead, use the vDSP_vsq function.
vDSP_vsq(a, 1, b, 1, n);
return 0;
}
更一般地说,除非您的算法非常简单,否则自动矢量化不太可能产生很好的效果。根据我的经验,矢量化技术的范围通常看起来像这样:
better performance worse performance
more effort less effort
+------+------+----------------------+----------------------------+-----------+
| | | | | |
| | use vectorized APIs | auto vectorization |
| skilled vector C | scalar code
hand written assembly unskilled vector C