我是OpenMP的新手,我正在尝试使用OpenMP对代码进行并行化:
#pragma omp parallel for
for(int k=0;k<m;k++)
{
for(int j=n-1;j>=0;j--)
{
outX[k+j*m] = inB2[j+n * k] / inA2[j*n + j];
for(int i=0;i<j;i++)
{
inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j];
}
}
}
对外循环进行并行化是非常简单的,但为了优化它,我想要对最内循环(对i迭代的循环)进行并行化。但是,当我尝试这样做时:
#pragma omp parallel for
for(int i=0;i<j;i++)
{
inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j];
}
编译器不会对内部循环进行矢量化(“因为可能的别名而导致为矢量化而循环”),这使得它运行得更慢。我使用gcc -ffast-math -std=c++11 -fopenmp -O3 -msse2 -funroll-loops -g -fopt-info-vec prog.cpp
感谢您的任何建议!
编辑:我正在为数组使用__restrict关键字。
EDIT2:有趣的是,当我在内循环中仅保留pragma并将其从外部移除时,gcc将向量化它。因此,当我尝试对两个周期进行并列化时,问题才会发生。
EDIT3:当我使用#pragma omp parallel for simd时,编译器将向量化循环。但它仍然比没有内部循环并行化更慢。
答案 0 :(得分:1)
我的猜测是,在你内部循环并行化后,你的编译器失去了inA2
,inB2
和outX
的轨道。默认情况下,它假定任何指针指向的任何内存区域可能彼此重叠。在C语言中,C99标准引入了restrict
关键字,该关键字通知编译器指针指向一个未被任何其他指针指向的内存块。 C ++没有这样的关键字,但幸运的是,g++
具有适当的扩展名。因此,尝试将__restrict
添加到循环触及的指针的声明中。例如,替换
double* outX;
与
double* __restrict outX;
答案 1 :(得分:1)
您是否尝试过首先使内环旋转?然后添加并行部分(这可能会导致性能降低,具体取决于缓存未命中)
AndroidSchedulers
总是需要一些时间让#pragma使用共享,公共等等...而且我没有对此进行测试。
答案 2 :(得分:1)
谢谢大家的回答。我设法使用#pragma omp parallel for simd
来矢量化内部循环,但程序比没有并行化时慢。我最终找到了一个稍微不同的算法来解决问题,这要快得多。
谢谢你的帮助!