如何解决OpenMP / OpenACC实施与gcc / PGI编译器之间的结果不一致
我有一个较大的Fortran程序正在尝试转换,以便计算密集型部分将在使用OpenMP和/或OpenACC的NVidia GPU上运行。在开发期间,我遇到了一些问题,以了解如何在模块中声明的变量如何在GPU(以及其中一些也在cpu)上执行的子例程中使用。因此,我通过尝试并添加相应的OpenMP和OpenACC指令,创建了一个小示例并进行了研究。在此消息的末尾,我已经包括了构成我的示例的三个文件。
就像我以为我已经理解了事情并且示例程序可以正常工作一样,我注意到了以下几点:
- 我使用OpenMP指令使用gcc 10.2编译程序:
gfortran -O3 -fopenmp -Wall -Wextra test_link.f90 parameters.f90 common_vars.f90 -o test_link
结果符合预期,即数组XMO的所有元素均为1,DCP为2,IS1为3,IS2为24。
- 我使用OpenACC指令使用PGI编译器19.10社区版编译程序:
pgfortran -O4 -acc -ta=tesla,cc35 -Minfo=all,mp,accel -Mcuda=cuda10.0 test_link.f90 common_vars.f90 parameters.f90 -o test_link
结果与上面相同。
- 我使用OpenACC指令使用gcc 10.2编译程序:
gfortran -O3 -fopenacc -Wall -Wextra test_link.f90 parameters.f90 common_vars.f90 -o test_link
XMO,DCP和IS1数组的结果正确,但是IS2的所有元素均为0。很容易验证变量NR的值为0以获得此结果。
我的理解是,示例中的OpenMP和OpenACC版本是等效的,但我无法弄清为什么OpenACC版本仅适用于PGI编译器而不适用于gcc。
如果可能,请提供不需要在代码中进行更改而仅在指令中进行更改的解决方案。正如我提到的,我的原始代码要大得多,包含更多的模块变量,并在要在GPU上执行的代码中调用了更多的子例程。对该代码进行更改将更加困难,显然,我更愿意仅在确实必要时进行更改。
提前谢谢!
我的示例文件如下。
File parameters.f90
MODULE ParaMETERS
IMPLICIT NONE
INTEGER,ParaMETER :: MAX_SOURCE_POSITIONS = 100
END MODULE ParaMETERS
File common_vars.f90
MODULE COMMON_VARS
USE ParaMETERS
IMPLICIT NONE
!$OMP DECLARE TARGET TO(NR)
INTEGER :: NR
!$ACC DECLARE copYIN(NR)
END MODULE COMMON_VARS
File test_link.f90
SUbroUTINE test()
USE COMMON_VARS
IMPLICIT NONE
!$OMP DECLARE TARGET
!$ACC ROUTINE SEQ
INTEGER I
I = NR
END SUbroUTINE TEST
PROGRAM TEST_LINK
USE COMMON_VARS
USE ParaMETERS
IMPLICIT NONE
INTERFACE
SUbroUTINE test()
!$OMP DECLARE TARGET
!$ACC ROUTINE SEQ
END SUbroUTINE TEST
END INTERFACE
REAL :: XMO(MAX_SOURCE_POSITIONS),DCP(MAX_SOURCE_POSITIONS)
INTEGER :: IS1(MAX_SOURCE_POSITIONS),IS2(MAX_SOURCE_POSITIONS)
INTEGER :: X,Y,Z,MAX_X,MAX_Y,MAX_Z,ISOUR
MAX_X = 3
MAX_Y = 4
MAX_Z = 5
NR = 6
!$OMP TARGET UPDATE TO(NR)
!$OMP TARGET MAP(TOFROM:IS1,IS2,DCP,XMO)
!$OMP TEAMS distribute ParaLLEL DO COLLAPSE(3)
!$ACC UPDATE DEVICE(NR)
!$ACC ParaLLEL LOOP GANG WORKER COLLAPSE(3) INDEPENDENT &
!$ACC copY(IS1,XMO)
DO X = 1,MAX_X
DO Y = 1,MAX_Y
DO Z = 1,MAX_Z
ISOUR = (X - 1)*MAX_Y*MAX_Z + (Y - 1)*MAX_Z + Z
XMO(ISOUR) = 1.0
DCP(ISOUR) = 2.0
IS1(ISOUR) = 3
IS2(ISOUR) = 4 * NR
CALL test()
ENDDO ! End of z loop
ENDDO ! End of y loop
ENDDO ! End of x loop
!$ACC END ParaLLEL LOOP
!$OMP END TEAMS distribute ParaLLEL DO
!$OMP END TARGET
DO X = 1,MAX_Z
ISOUR = (X - 1)*MAX_Y*MAX_Z + (Y - 1)*MAX_Z + Z
WRITE(*,*) 'ISOUR = ',ISOUR,'XMO = ',XMO(ISOUR),'DCP = ',DCP(ISOUR),'IS1 = ',IS1(ISOUR),'IS2 = ',IS2(ISOUR)
ENDDO ! End of z loop
ENDDO ! End of y loop
ENDDO ! End of x loop
END PROGRAM TEST_LINK
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。