OpenACC和减少输出在每次执行时递增总和

时间:2014-09-27 17:16:32

标签: 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标准:

  

在退出数据指令上,数据被复制回本地内存和   释放。

似乎sum 已取消分配,而是在程序的每次运行中重复使用(并递增)。此外,+指令中的reduction运算符会将缩减变量初始化为0,因此,即使sum未在copyin之间取消分配,也不会发生这种情况。处决。

我可以通过在create指令中使用sum代替enter data代替sum = 0,或者在单个群组中设置#pragma acc parallel present(sum) num_gangs(1) num_workers(1) sum = 0; 来避免此行为,单工内核:

{{1}}

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

1 个答案:

答案 0 :(得分:2)

您误解了简化运算符初始化值的含义。参考openACC specification,第20-21页:

  

并行构造允许使用reduction子句。它指定一个简化运算符和一个或多个标量变量。对于每个变量,为每个并行组创建一个私有副本,并为该操作符初始化。在该地区的末尾,价值观   使用简化运算符组合每个组,并将结果与原始变量的值组合并存储在原始变量中。

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

因此,您必须正确初始化sum,或许可以使用您在问题中列出的方法之一。

此外,虽然这不是问题的症结所在,但请注意,否则释放和分配对内存的内容没有任何影响。在没有正确初始化的情况下,在该点中分配的新变量将在该位置中明确地获取该值。