使用嵌套的 OpenACC 例程传递参考参数
Reference Argument Passing with Nested OpenACC Routines
我正在尝试使用 OpenACC 并行化某些 Fortran 90 代码,其中并行化循环调用顺序例程。当我尝试使用 PGI Fortran 编译器 (2020.4) 运行 代码时,我收到一条错误消息,指出传递引用参数会阻止并行化。
我的理解是,这可能是因为一个例程存在于主机上,而另一个例程存在于设备上,但我不清楚我可能在哪里遗漏了导致这种结果的编译指示。
调用例程的基本结构为:
subroutine OuterRoutine(F,G,X,Y)
real(wp), dimension(:,:), intent(IN) :: X
real(wp), dimension(:,:), intent(IN) :: Y
real(wp), dimension(1,PT), intent(OUT) :: F
real(wp), dimension(N_p,PT), intent(OUT) :: G
! Local Variables
integer :: t, i, j
!$acc data copyin(X,Y), copyout(F,G)
!$acc parallel loop
do t = 1,PT,1
!$acc loop collapse(2) reduction(+:intr)
do i = 1,N_int-1,1
do j = 1,N_int-1,1
G(i,j) = intgrdJ2(X(i,j),X(j,i),Y(i,j),Y(j,i),t)
end do
end do
!$acc end loop
!$acc end parallel loop
!$acc end data
end subroutine OuterRoutine
被调用的函数是:
function intgrdJ2(z,mu,p,q,t)
!$acc routine seq
real(wp), intent(IN) :: z, mu, p, q
integer, intent(IN) :: t
real(wp) :: intgrdJ2
! Local Variables
real(wp) :: mu2
real(wp), dimension(N_p) :: nu_m2, psi_m2
integer :: i
mu2 = (mu*fh_pdf(z,mu,p))/f_pdf(z,mu,p)
do i = 1,N_p,1
nu_m2(i) = interpValue(mu2,mugrid,nu_knots(:,i,t))
psi_m2(i) = interpValue(mu2,mugrid,psi_knots(:,i,t))
end do
intgrdJ2 = nu_m2(i)*psi_m2(i)
end function intgrdJ2
例程interpValue、fh_pdf和f_pdf都包含在一个用过的模块中,记为!$acc routine seq。变量mugrid、nu_knots、psi_knots都是module-级别变量,在调用 OuterRoutine.
之前复制到设备中
当我 运行 代码时,我从编译器得到这样的输出:
intgrdj2:
576, Generating acc routine seq
Generating Tesla code
593, Reference argument passing prevents parallelization: mu2
其中 593 指的是“nu_m2(i) = ...”行。
我的理解是,由于变量 mu2 是在顺序例程中声明的标量,每个线程都应该有自己的变量副本,我不需要在我声明数据区域时明确声明它是私有的。从阅读 this post 看来,问题可能与例程所在的位置有关(主机与设备)。但是,似乎所有相关部分都应该在设备上,因为我指定例程是顺序的。
作为第一次使用 OpenACC 的用户,如果能对我可能忽略的内容进行任何解释,我们将不胜感激!
My understanding is that since the variable mu2 is a scalar declared
inside of the sequential routine, each thread should have it's own
copy of the variable, and I don't need to explicitly declare it to be
private when I declare the data region
大多数情况下都是如此。但这里可能发生的情况是,由于默认情况下 Fortran 通过引用传递变量,因此编译器必须假设它的引用可以由模块变量获取。不太可能,但有可能。
解决此问题的典型方法是按值传递标量,即将“值”属性添加到“interpValue”中的参数声明。或者,您可以通过在“i”循环上添加“!$acc loop seq private(mu2)”来显式私有化“mu2”。
现在该消息可能只是表明编译器无法 auto-parallelize 此循环。但由于它是在顺序例程中,所以这无关紧要,您可以安全地忽略该消息。不过,我没有完整的上下文,所以不能 100% 确定这一点。
我正在尝试使用 OpenACC 并行化某些 Fortran 90 代码,其中并行化循环调用顺序例程。当我尝试使用 PGI Fortran 编译器 (2020.4) 运行 代码时,我收到一条错误消息,指出传递引用参数会阻止并行化。
我的理解是,这可能是因为一个例程存在于主机上,而另一个例程存在于设备上,但我不清楚我可能在哪里遗漏了导致这种结果的编译指示。
调用例程的基本结构为:
subroutine OuterRoutine(F,G,X,Y)
real(wp), dimension(:,:), intent(IN) :: X
real(wp), dimension(:,:), intent(IN) :: Y
real(wp), dimension(1,PT), intent(OUT) :: F
real(wp), dimension(N_p,PT), intent(OUT) :: G
! Local Variables
integer :: t, i, j
!$acc data copyin(X,Y), copyout(F,G)
!$acc parallel loop
do t = 1,PT,1
!$acc loop collapse(2) reduction(+:intr)
do i = 1,N_int-1,1
do j = 1,N_int-1,1
G(i,j) = intgrdJ2(X(i,j),X(j,i),Y(i,j),Y(j,i),t)
end do
end do
!$acc end loop
!$acc end parallel loop
!$acc end data
end subroutine OuterRoutine
被调用的函数是:
function intgrdJ2(z,mu,p,q,t)
!$acc routine seq
real(wp), intent(IN) :: z, mu, p, q
integer, intent(IN) :: t
real(wp) :: intgrdJ2
! Local Variables
real(wp) :: mu2
real(wp), dimension(N_p) :: nu_m2, psi_m2
integer :: i
mu2 = (mu*fh_pdf(z,mu,p))/f_pdf(z,mu,p)
do i = 1,N_p,1
nu_m2(i) = interpValue(mu2,mugrid,nu_knots(:,i,t))
psi_m2(i) = interpValue(mu2,mugrid,psi_knots(:,i,t))
end do
intgrdJ2 = nu_m2(i)*psi_m2(i)
end function intgrdJ2
例程interpValue、fh_pdf和f_pdf都包含在一个用过的模块中,记为!$acc routine seq。变量mugrid、nu_knots、psi_knots都是module-级别变量,在调用 OuterRoutine.
之前复制到设备中当我 运行 代码时,我从编译器得到这样的输出:
intgrdj2:
576, Generating acc routine seq
Generating Tesla code
593, Reference argument passing prevents parallelization: mu2
其中 593 指的是“nu_m2(i) = ...”行。
我的理解是,由于变量 mu2 是在顺序例程中声明的标量,每个线程都应该有自己的变量副本,我不需要在我声明数据区域时明确声明它是私有的。从阅读 this post 看来,问题可能与例程所在的位置有关(主机与设备)。但是,似乎所有相关部分都应该在设备上,因为我指定例程是顺序的。
作为第一次使用 OpenACC 的用户,如果能对我可能忽略的内容进行任何解释,我们将不胜感激!
My understanding is that since the variable mu2 is a scalar declared inside of the sequential routine, each thread should have it's own copy of the variable, and I don't need to explicitly declare it to be private when I declare the data region
大多数情况下都是如此。但这里可能发生的情况是,由于默认情况下 Fortran 通过引用传递变量,因此编译器必须假设它的引用可以由模块变量获取。不太可能,但有可能。
解决此问题的典型方法是按值传递标量,即将“值”属性添加到“interpValue”中的参数声明。或者,您可以通过在“i”循环上添加“!$acc loop seq private(mu2)”来显式私有化“mu2”。
现在该消息可能只是表明编译器无法 auto-parallelize 此循环。但由于它是在顺序例程中,所以这无关紧要,您可以安全地忽略该消息。不过,我没有完整的上下文,所以不能 100% 确定这一点。