我有一种情况需要多次重复循环的特定迭代。所以,在那个特定的迭代中,我将索引缩减一步,以便循环索引的下一个增量没有区别。
这种方法是我必须实现的方法,适用于多线程OpenMP代码。但是,它不适用于OpenACC(对于多核和特斯拉目标)。我收到以下错误:
Floating point exception (core dumped)
以下是两种情况的代码:
#include <stdio.h>
#include <omp.h>
#include <unistd.h>
int main() {
int x = 52;
int count = 5;
int i;
omp_set_num_threads(6);
#pragma omp parallel for
for(i=0;i<100;i++) {
if(i == x) {
printf("%d\n", i);
i--;
count--;
if(count == 0)
x = 10000;
}
}
int gpu_count = 0;
count = 5;
x = 52;
#pragma acc parallel loop independent
for(i=0;i<1000000;i++) {
if(i == x) {
#pragma acc atomic
gpu_count++;
i--;
count--;
if(count == 0)
x = 2000000;
}
}
printf("gpu_count: %d\n", gpu_count);
return 0;
}
对于OpenMP,我得到了正确的输出:
52
52
52
52
52
但是,对于OpenACC,我得到了上述错误。
如果我评论第35行(i - ;),,代码将被正确执行,它将输出重复迭代次数(即1)。
注意:我正在使用PGI 16.5和Geforce GTX 970以及CUDA 7.5。
我用PGI编译器编译如下:
pgcc -mp -acc -ta=multicore -g f1.c
所以,我的问题是:为什么我看到这样的行为?我不能在OpenACC中更改循环索引变量吗?
答案 0 :(得分:1)
您的OpenMP版本有误。您依赖于块大小大于“count”的静态计划。如果增加OMP线程的数量使得块大小小于count,或者如果更改时间表以交错块(即“schedule(static,1)”),那么您将得到错误的答案。 “x”和“count”也有竞争条件。
请注意,OpenACC调度更像是OpenMP“static,1”,因此向量可以访问工作者(也就是CUDA warp)的连续内存块。所以你的算法也不会在这里工作。
此外,通过使用“independent”子句(使用“并行循环”时暗示),您向编译器断言此循环不包含依赖项或用户将通过“atomic”指令处理它们。但是,更改循环体内的循环索引变量将创建循环依赖关系,因为循环索引的值取决于前一次迭代是否更改了它的值。
编辑:下面是一个示例,它是代码的可并行化版本。
% cat test2.c
#include <stdio.h>
#include <omp.h>
#include <unistd.h>
int main() {
int x = 52;
int count = 5;
int i;
int mycnt;
#pragma omp parallel for schedule(static,1) private(mycnt)
for(i=0;i<100;i++) {
if(i == x) {
mycnt = count;
while(mycnt > 0) {
printf("%d\n", i);
mycnt--;
}
}
}
#ifdef _OPENACC
int gpu_count = 0;
#pragma acc parallel loop reduction(+:gpu_count)
for(i=0;i<1000000;i++) {
if(i == x) {
mycnt = count;
while(mycnt > 0) {
gpu_count++;
mycnt--;
}
}
}
printf("gpu_count: %d\n", gpu_count);
#endif
return 0;
}
% pgcc -fast -mp -acc test2.c -Minfo=mp,acc
main:
13, Parallel region activated
Parallel loop activated with static cyclic schedule
24, Barrier
Parallel region terminated
25, Accelerator kernel generated
Generating Tesla code
25, Generating reduction(+:gpu_count)
26, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
29, #pragma acc loop seq
29, Loop carried scalar dependence for gpu_count at line 30
% a.out
52
52
52
52
52
gpu_count: 5