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 上面发布的结果相同。