为什么以下代码:
#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}}
但这并不令人满意,因为它需要昂贵的主机到设备数据副本,分别需要内核启动。为什么我的程序如此表现?
答案 0 :(得分:2)
您误解了简化运算符初始化值的含义。参考openACC specification,第20-21页:
并行构造允许使用reduction子句。它指定一个简化运算符和一个或多个标量变量。对于每个变量,为每个并行组创建一个私有副本,并为该操作符初始化。在该地区的末尾,价值观 使用简化运算符组合每个组,并将结果与原始变量的值组合并存储在原始变量中。
这意味着整体减少问题被分解成碎片,每一件由一个团伙处理。该组处理的问题部分将使用指示的初始化值作为缩减变量。但是,当创建最终结果时,每个组的单个结果将与原始变量的值(在您的情况下为sum
)组合,这将是结果。
因此,您必须正确初始化sum
,或许可以使用您在问题中列出的方法之一。
此外,虽然这不是问题的症结所在,但请注意,否则释放和分配对内存的内容没有任何影响。在没有正确初始化的情况下,在该点中分配的新变量将在该位置中明确地获取该值。