c++ - 每次执行时,OpenACC 总和减少输出递增总和

标签 c++ cuda gpgpu openacc pgi

为什么会出现下面的代码:

#include <iostream>

int main(int argc, char const *argv[])
{
    int sum = 0;
    int *array;
    array = new int [100];

    #pragma acc enter data create(array[0:100],sum)

    #pragma acc parallel loop present(array[0:100])
    for (int i = 0; i < 100; ++i)
    {
        array[i] = 1;
    }

    #pragma acc parallel loop present(array[0:100],sum) reduction(+:sum)
    for (int i = 0; i < 100; ++i)
    {
        sum += array[i];
    }

    #pragma acc exit data delete(array[0:100]) copyout(sum)

    std::cout << sum << std::endl;

    return 0;
}

每次执行都返回不同的结果?

$ pgcpp -acc -Minfo main.cpp
main:
      7, Generating enter data create(sum)
         Generating enter data create(array[:100])
         Generating present(array[:100])
         Accelerator kernel generated
         12, #pragma acc loop gang, vector(256) /* blockIdx.x threadIdx.x */
      7, Generating Tesla code
     15, Generating present(array[:100])
         Generating present(sum)
         Accelerator kernel generated
         18, #pragma acc loop gang, vector(256) /* blockIdx.x threadIdx.x */
         20, Sum reduction generated for sum
     15, Generating Tesla code
     25, Generating exit data copyout(sum)
         Generating exit data delete(array[:100])
$ ./a.out
100
$ ./a.out
200
$ ./a.out
300
$ ./a.out
400

根据 OpenACC 标准:

On an exit data directive, the data is copied back to the local memory and deallocated.

sum 似乎没有被释放,而是在程序的每次运行中被重新使用(并递增)。此外,reduction 指令中的 + 运算符将 reduction 变量初始化为 0,因此即使 sum 未在执行之间释放。

我可以通过在 enter data 指令中为 sum 使用 copyin 而不是 create 来避免这种行为, 或者在单个 gang, single worker 内核中设置 sum = 0:

#pragma acc parallel present(sum) num_gangs(1) num_workers(1)
sum = 0;

但这并不令人满意,因为它需要昂贵的主机到设备数据拷贝,或者内核启动。为什么我的程序表现如此?

最佳答案

您误解了归约运算符初始化值的含义。引用openACC specification , 第 20-21 页:

The reduction clause is allowed on the parallel construct. It specifies a reduction operator and one or more scalar variables. For each variable, a private copy is created for each parallel gang and initialized for that operator. At the end of the region, the values for each gang are combined using the reduction operator, and the result combined with the value of the original variable and stored in the original variable.

这意味着整体缩减问题被分解成多个部分,每个部分由一个团队处理。该帮派处理的问题部分将使用指示的归约变量的初始化值。但是,当创建最终结果时,每个组的单独结果将与原始变量的值(在您的情况下为 sum)组合,这就是结果。

因此您必须正确初始化 sum,也许使用您在问题中概述的方法之一。

此外,尽管这不是问题的症结所在,但请注意,释放和分配都不会对内存内容产生任何影响。在那个位置分配的新变量,如果没有适当的初始化,将获取当前在那个位置的值。

关于c++ - 每次执行时,OpenACC 总和减少输出递增总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26077195/

相关文章:

c++ - cuda推力中的多项替换

glsl - GPGPU - 有效的乒乓球技术?

ios - 使用 GPUImage 并行处理 GPU 和 CPU

c++ - 为什么要在 PE 文件中创建不同的代码/数据/bss 部分?

cuda - 关于字长的银行冲突

java - 是否有任何支持 CUDA 的 JVM 实现?

cuda - CURAND 库 - 编译错误 - 对函数的 undefined reference

c++ - 模板类友元函数的内部类

c++ - 使用c++递归解决迷宫,无法处理异常情况

c++ - 如何使用 C 的 sprintf() 安全地格式化 float / double ?