我想将SIMD矢量化用于替换计算函数的傅里叶变换。它可以概括为:
double f_1(int s); // expensive
double f_2(int s, int k); // cheap but frequent
void accumulate(double *sum, int samples, int freqs) {
for (int s=0; s<samples; s++) {
double data = f_1(s);
for (int k=0; k<freqs; k++)
sum[k] += data * f_2(s, k);
}
}
直接前进的方式是在outso循环s上并行化并减少sum [k],但它的直接大小会溢出缓存。然而,仅仅对内环进行矢量化将不会改善昂贵的函数f_1。是否有一个很好的方法来获得两者,f_1的矢量化和s的积累?如果可能,尽可能使用OpenMP,而无需手动分块。
编辑: 到目前为止,我发现的最好的方法是手动分块。但是,以这种方式重构代码是一项重要任务。它很好地验证了f_1,但是gcc似乎不喜欢这样做f_2。也许是一个错误...
#pragma omp declare simd linear(s)
double f_1(int s); // expensive
#pragma omp declare simd uniform(s) linear(k)
double f_2(int s, int k); // cheap but frequent
void accumulate(double *sum, int samples, int freqs) {
const int N = 8;
for (int s=0; s<samples; s+=N) {
double data[N];
#pragma omp simd
for (int i=0; i<N; i++)
data[i] = f_1(s+i);
#pragma omp simd safelen(N)
for (int k=0; k<freqs; k++) {
for (int i=0; i<N; i++)
sum[k] += data[i] * f_2(s+i, k);
}
}
}