OpenACC:为什么更新数组取决于更新指令的位置



我是openacc的新手。我正试图用它来加速粒子代码。然而,我不明白为什么在主机上更新数组(下面程序中的eta)时,它会根据"!$acc update self"的位置给出不同的结果。这是一个重新产生这个问题的代码:

program approximateFun
use funs
use paras_mod
integer :: Nx
real(dp) :: dx
real(dp), dimension(:), allocatable :: x, eta
real(dp), dimension(5) :: xp, fAtxp
!$acc declare create(Nx)
!$acc declare create(x)
!$acc declare create(eta)
!$acc declare create(dx)
!$acc declare create(fAtxp)
!$acc declare create(xp)
Nx = 16
!$acc update device(Nx)
xp = (/3.9, 4.1, 4.5, 5.0, 5.6/)
!$acc update device(xp)
allocate(x(1 : Nx))
allocate(eta(1 : Nx))
eta = 0.0d0
dx = 2 * pi / (Nx - 1)
!$acc update device(dx)
do i = 1, Nx
x(i) = (i - 1.0d0) * dx
end do
!$acc update device(x)

call calc_etaVec(x, Nx, eta)
!$acc update self(eta)        ! gives the correct results
!$acc parallel loop present(dx, xp, eta, fAtxp)
do i = 1, 5
call calcFunAtx(xp(i), dx, eta, fAtxp(i))
end do
!$acc update self (fAtxp)
!!$acc update self(eta) !---> gives wrong result
write(6, *) 'eta', eta
do i = 1, 5
write(6, *) 'xp, fAtxp', xp(i), fAtxp(i)
end do
deallocate(x)
deallocate(eta)
end program approximateFun

上一个程序使用以下模块

MODULE funs
use paras_mod
implicit none
CONTAINS
subroutine calc_etaVec(x, nx, eta)
integer, intent(in) :: nx
real(dp), dimension(:), intent(in) :: x
real(dp), dimension(:), intent(out) :: eta
integer :: i
!$acc parallel loop present(x, eta)
do i = 1, nx
eta(i) = sin(x(i))
end do
end subroutine
subroutine calcFunAtx(xp, dx, eta, fAtx)
real(dp), intent(in) :: xp, dx
real(dp), dimension(:), intent(in) :: eta
real(dp), intent(out) :: fAtx
integer :: idx
!$acc routine seq
idx = 1 + floor(xp / dx)
fAtx = eta(idx)
end subroutine calcFunAtx
END MODULE

module paras_mod
implicit none
save
INTEGER, PARAMETER :: dp = selected_real_kind(14,300)
REAL(dp), PARAMETER :: PI=4.0d0*atan(1.0d0)
end module paras_mod

当在call calc_etaVec(x, Nx, eta)之后直接使用!$acc update self(eta)时,eta被正确更新。但是,当在循环之后使用时,只有前五个元素是正确的,而其余的都是零。这背后的原因是什么?

感谢

call calc_etaVec(x, Nx, eta)之后直接使用!$acc update self(eta)时的输出为

0.000000000000000        0.4067366430758002
0.7431448254773941        0.9510565162951535        0.9945218953682734 
0.8660254037844388        0.5877852522924732        0.2079116908177597 
-0.2079116908177591       -0.5877852522924730       -0.8660254037844384 
-0.9945218953682732       -0.9510565162951536       -0.7431448254773946 
-0.4067366430758009       -2.4492935982947064E-016

这是正确的。然而,当在循环后使用时,输出为

0.000000000000000        0.4067366430758002
0.7431448254773941        0.9510565162951535        0.9945218953682734
0.000000000000000         0.000000000000000         0.000000000000000
0.000000000000000         0.000000000000000         0.000000000000000
0.000000000000000         0.000000000000000         0.000000000000000
0.000000000000000         0.000000000000000

这个问题一直令人困惑,直到我确定它是编译器错误。我已经提交了一份问题报告,TPR#32673,并将其发送给工程部进行审查。

当设置显示数据移动的环境变量NV_ACC_NOTIFY=2时,我发现编译器只复制了40个字节,而正确的是128个字节。然而,如果我删除";eta";从前面的现在句来看,那是正确的。

#ifdef WORKS
!$acc parallel loop present(dx, fAtxp)
#else
!$acc parallel loop present(dx, fAtxp, eta)
#endif
do i = 1, 5
call calcFunAtx(xp(i), dx, eta, fAtxp(i))
end do

此外,只有在declare-create指令中使用可分配程序时才会发生这种情况。如果您切换到使用数据区域,则不会出现问题。也许是我们以前没有看到它的原因(看起来这些bug是从2020年年中开始出现的)。很少在模块之外的任何程序中使用declare指令。

相关内容

  • 没有找到相关文章

最新更新