修改OpenACC

时间:2017-03-13 18:46:39

标签: loops openmp openacc

我有一种情况需要多次重复循环的特定迭代。所以,在那个特定的迭代中,我将索引缩减一步,以便循环索引的下一个增量没有区别。

这种方法是我必须实现的方法,适用于多线程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中更改循环索引变量吗?

1 个答案:

答案 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