GNU FORTRAN OpenACC 访问设备上派生类型的可分配成员
GNU FORTRAN OpenACC Accessing an allocatable member of a derived type on device
我需要访问设备上派生类型的可分配成员。我找到了一个很好的解决方案。但是,它使用 PGI 编译器。我不知道如何安装带有所有许可障碍的编译器。所以我正在寻找 GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0.
的解决方案
下面的示例程序 运行 在没有 -fopenacc 标志的情况下也很好。但是,一旦启用该标志,我就会收到以下错误:
libgomp: cuStreamSynchronize error: an illegal memory access was encountered
这是我在没有 OpenACC 的情况下 运行 代码(保存在名为:Whosebug.f95 的文件中)的方式:
$ gfortran -c Whosebug.f95
$ gfortran Whosebug.o -o Whosebug
$ ./Whosebug
以下是我 运行 使用 OpenACC 的代码:
$ gfortran -fopenacc -c Whosebug.f95
$ gfortran -fopenacc Whosebug.o -o Whosebug
$ ./Whosebug
请问有解决办法吗?这是示例代码:
module modTest2
use openacc
implicit none
type :: Container
sequence
integer :: n
integer, allocatable :: arr(:)
end type Container
interface Container
procedure :: new_Container
end interface Container
contains
type(Container) function new_Container(n)
integer, intent(in) :: n
allocate(new_Container%arr(n))
end function new_Container
end module modTest2
program test2
use modTest2
implicit none
integer :: n, i
type(Container) :: c
print *, "Enter array size: "
read *, n
print *, "Allocating..."
c = Container(n)
print *, "Allocation complete!"
print *, "Initializing..."
!$acc data copyin(c)
!$acc parallel loop present(c)
do i = 1, n
c%arr(i) = i*20
end do
!$acc end data
print *, "Initialization complete..."
do i = 1, n
print *, i, c%arr(i)
end do
end program test2
问题是您需要对“c%arr”进行深拷贝。默认情况下,复制子句执行浅拷贝。因此,对于“copy(c)”,它正在复制设备上无法访问的“arr”的主机地址。
由于我在 NVIDIA 和 NVHPC 编译器团队(又名 PGI)工作,我对 gfortran 没有深入了解,但假设以下代码也适用于他们。我更喜欢使用非结构化数据区域,因此包括结构化和非结构化版本。请注意,顺序很重要,因为“c”应该在“c%arr”之前在设备上创建,这样编译器就可以隐式地将它“附加”到“c”。 “attach”基本上是在“c”的设备副本中填写指向“arr”的设备指针。颠倒顺序将需要代码通过“附加”子句显式附加或调用“acc_attach”API.
示例:
% cat test2.f90
module modTest2
use openacc
implicit none
type :: Container
sequence
integer :: n
integer, allocatable :: arr(:)
end type Container
interface Container
procedure :: new_Container
end interface Container
contains
type(Container) function new_Container(n)
integer, intent(in) :: n
allocate(new_Container%arr(n))
end function new_Container
end module modTest2
program test2
use modTest2
implicit none
integer :: n, i
type(Container) :: c
print *, "Enter array size: "
read *, n
print *, "Allocating..."
c = Container(n)
print *, "Allocation complete!"
print *, "Initializing..."
!acc enter data copyin(c) create(c%arr)
!$acc data copyin(c) copyout(c%arr)
!$acc parallel loop present(c)
do i = 1, n
c%arr(i) = i*20
end do
!$acc end data
!acc exit data copyout(c%arr) delete(c)
print *, "Initialization complete..."
do i = 1, n
print *, i, c%arr(i)
end do
end program test2
% nvfortran test2.f90 -acc; a.out
Enter array size:
1024
Allocating...
Allocation complete!
Initializing...
Initialization complete...
1 20
2 40
3 60
4 80
5 100
6 120
7 140
... cut ...
1020 20400
1021 20420
1022 20440
1023 20460
1024 20480
请注意,包括编译器在内的 NVHPC SDK 是免费提供的。请参阅:https://developer.nvidia.com/hpc-sdk
当前的 GCC 诊断 !$acc data copyin(c) copyout(c%arr)
以及 !$acc enter data copyin(c) create(c%arr)
和 !$acc exit data copyout(c%arr) delete(c)
,而不是 Syntax error in OpenMP variable list
。目前尚不清楚这是否意味着 OpenACC 支持——我知道在条款处理顺序等方面存在未解决的问题,OpenACC 技术委员会需要研究这些问题。 (我也是该委员会的成员。)所以 PGI/NVHPC 正在实施的可能实际上不是标准的 OpenACC。
就是说,我能够使程序与 GCC/OpenACC 一起工作,如下所示:
将 !$acc data copyin(c) copyout(c%arr)
拆分为两个嵌套数据区域:
!$acc data copyin(c)
!$acc data copyout(c%arr)
[...]
!$acc end data
!$acc end data
或者,代替 !$acc enter data copyin(c) create(c%arr)
和 !$acc exit data copyout(c%arr) delete(c)
将它们拆分为:
!$acc enter data copyin(c)
!$acc enter data create(c%arr)
[...]
!$acc exit data copyout(c%arr)
!$acc exit data delete(c)
对于这两种变体,我得到的结果与 Mat 上面发布的结果相同。
我需要访问设备上派生类型的可分配成员。我找到了一个很好的解决方案
下面的示例程序 运行 在没有 -fopenacc 标志的情况下也很好。但是,一旦启用该标志,我就会收到以下错误:
libgomp: cuStreamSynchronize error: an illegal memory access was encountered
这是我在没有 OpenACC 的情况下 运行 代码(保存在名为:Whosebug.f95 的文件中)的方式:
$ gfortran -c Whosebug.f95
$ gfortran Whosebug.o -o Whosebug
$ ./Whosebug
以下是我 运行 使用 OpenACC 的代码:
$ gfortran -fopenacc -c Whosebug.f95
$ gfortran -fopenacc Whosebug.o -o Whosebug
$ ./Whosebug
请问有解决办法吗?这是示例代码:
module modTest2
use openacc
implicit none
type :: Container
sequence
integer :: n
integer, allocatable :: arr(:)
end type Container
interface Container
procedure :: new_Container
end interface Container
contains
type(Container) function new_Container(n)
integer, intent(in) :: n
allocate(new_Container%arr(n))
end function new_Container
end module modTest2
program test2
use modTest2
implicit none
integer :: n, i
type(Container) :: c
print *, "Enter array size: "
read *, n
print *, "Allocating..."
c = Container(n)
print *, "Allocation complete!"
print *, "Initializing..."
!$acc data copyin(c)
!$acc parallel loop present(c)
do i = 1, n
c%arr(i) = i*20
end do
!$acc end data
print *, "Initialization complete..."
do i = 1, n
print *, i, c%arr(i)
end do
end program test2
问题是您需要对“c%arr”进行深拷贝。默认情况下,复制子句执行浅拷贝。因此,对于“copy(c)”,它正在复制设备上无法访问的“arr”的主机地址。
由于我在 NVIDIA 和 NVHPC 编译器团队(又名 PGI)工作,我对 gfortran 没有深入了解,但假设以下代码也适用于他们。我更喜欢使用非结构化数据区域,因此包括结构化和非结构化版本。请注意,顺序很重要,因为“c”应该在“c%arr”之前在设备上创建,这样编译器就可以隐式地将它“附加”到“c”。 “attach”基本上是在“c”的设备副本中填写指向“arr”的设备指针。颠倒顺序将需要代码通过“附加”子句显式附加或调用“acc_attach”API.
示例:
% cat test2.f90
module modTest2
use openacc
implicit none
type :: Container
sequence
integer :: n
integer, allocatable :: arr(:)
end type Container
interface Container
procedure :: new_Container
end interface Container
contains
type(Container) function new_Container(n)
integer, intent(in) :: n
allocate(new_Container%arr(n))
end function new_Container
end module modTest2
program test2
use modTest2
implicit none
integer :: n, i
type(Container) :: c
print *, "Enter array size: "
read *, n
print *, "Allocating..."
c = Container(n)
print *, "Allocation complete!"
print *, "Initializing..."
!acc enter data copyin(c) create(c%arr)
!$acc data copyin(c) copyout(c%arr)
!$acc parallel loop present(c)
do i = 1, n
c%arr(i) = i*20
end do
!$acc end data
!acc exit data copyout(c%arr) delete(c)
print *, "Initialization complete..."
do i = 1, n
print *, i, c%arr(i)
end do
end program test2
% nvfortran test2.f90 -acc; a.out
Enter array size:
1024
Allocating...
Allocation complete!
Initializing...
Initialization complete...
1 20
2 40
3 60
4 80
5 100
6 120
7 140
... cut ...
1020 20400
1021 20420
1022 20440
1023 20460
1024 20480
请注意,包括编译器在内的 NVHPC SDK 是免费提供的。请参阅:https://developer.nvidia.com/hpc-sdk
当前的 GCC 诊断 !$acc data copyin(c) copyout(c%arr)
以及 !$acc enter data copyin(c) create(c%arr)
和 !$acc exit data copyout(c%arr) delete(c)
,而不是 Syntax error in OpenMP variable list
。目前尚不清楚这是否意味着 OpenACC 支持——我知道在条款处理顺序等方面存在未解决的问题,OpenACC 技术委员会需要研究这些问题。 (我也是该委员会的成员。)所以 PGI/NVHPC 正在实施的可能实际上不是标准的 OpenACC。
就是说,我能够使程序与 GCC/OpenACC 一起工作,如下所示:
将 !$acc data copyin(c) copyout(c%arr)
拆分为两个嵌套数据区域:
!$acc data copyin(c)
!$acc data copyout(c%arr)
[...]
!$acc end data
!$acc end data
或者,代替 !$acc enter data copyin(c) create(c%arr)
和 !$acc exit data copyout(c%arr) delete(c)
将它们拆分为:
!$acc enter data copyin(c)
!$acc enter data create(c%arr)
[...]
!$acc exit data copyout(c%arr)
!$acc exit data delete(c)
对于这两种变体,我得到的结果与 Mat 上面发布的结果相同。