我正在尝试将工人专用阵列与OpenACC配合使用,但是我一直得到错误的结果。我猜发生了某种竞争状况问题,但我找不到位置。
我正在使用PGI编译器(18.10,OpenPower)并使用:
进行编译pgf90 -gopt -O3 -Minfo=all -Mcuda=ptxinfo -acc -ta=tesla:cc35 main.F90
这是我要实现的目标的一个最小示例:
#define lx 7000
#define ly 500
program test
implicit none
integer :: tmp(ly,1), a(lx,ly), b(lx,ly)
integer :: x,y,i
do x=1,lx
do y=1,ly
a(x,y) = x+y
end do
end do
!$acc parallel num_gangs(1)
!$acc loop worker private(tmp)
do x=1,lx
!$acc loop vector
do y=1,ly
tmp(y,1) = -a(x,y)
end do
!$acc loop vector
do y=1,ly
b(x,y) = -tmp(y,1)
end do
end do
!$acc end parallel
print *, "check"
do x=1,lx
do y=1,ly
if(b(x,y) /= x+y) print *, x, y, b(x,y), x+y
end do
end do
print*, "end"
end program
我原本希望得到b == a,但事实并非如此。
请注意,我定义了tmp(ly,1)
,因为将tmp(ly)
定义为一维数组时可以得到预期的结果。即使它与一维阵列兼容,我也不确定它是否完全遵守OpenACC标准。
我在这里想念东西吗?
编辑:最后一个循环检查a == b,并输出错误的值。预期的输出(我在禁用OpenACC的情况下得到)是:
check
end
启用OpenACC后,我得到的是这样的结果(运行之间的变化):
check
1 1 5 2
1 2 6 3
1 3 7 4
[...]
end
答案 0 :(得分:1)
看起来像一个编译器问题,其中“ tmp”由工作程序共享,而不是每个工作程序都获得私有副本。反过来,这会在您的代码中导致竞争状态。
我已向PGI(TPR#27025)提交了问题报告,并将其发送给我们的工程师进行进一步调查。
解决方法是在外循环上使用“ gang”而不是“ worker”,或者您要注意,将“ tmp”作为一维数组。
答案 1 :(得分:0)
这两个acc loop
!$acc loop vector
do y=1,ly
tmp(y,1) = -a(x,y)
end do
!$acc loop vector
do y=1,ly
b(x,y) = -tmp(y,1)
end do
将同时在gpu上执行。也就是说,它们是并行执行的。为了确保tmp
在第二个循环中被使用之前在第一个循环中被正确校正,它们必须位于不同的acc parallel
结构上。
正确的代码如下:
do x=1,lx
!$acc parallel loop
do y=1,ly
tmp(y,1) = -a(x,y)
end do
!$acc parallel loop
do y=1,ly
b(x,y) = -tmp(y,1)
end do
end do