使用OpenACC加速Fortran程序时如何创建仅在GPU上使用的数组?
解决方案
OpenACC 2.5及更高版本已支持仅在设备端分配数组、无需占用主机内存的功能,有两种常用实现方式:
方案1:使用device_resident声明设备驻留数组
直接在数组声明时添加!$acc declare device_resident修饰符,标记该数组仅存在于设备端,全程不需要在主机端执行分配/释放操作,也不能在主机端读写该数组。
修改后的示例代码如下:
program test implicit none integer, parameter :: n = 1000 real :: total real, allocatable :: array(:) real, allocatable :: array_d(:) ! 标记array_d为仅设备驻留数组 !$acc declare device_resident(array_d) allocate(array(n)) ! 无需在主机端分配array_d内存 array(:) = 1e0 !$acc data copy(array) copyout(total) ! 无需再重复create(array_d) !$acc kernels array_d(:) = array(:) !$acc end kernels !$acc kernels total = sum(array_d) !$acc end kernels !$acc end data print *, sum(array) print *, total deallocate(array) ! 无需在主机端释放array_d,如需手动释放可执行 !$acc exit data delete(array_d) end program
该方案适合设备数组需要在程序全生命周期使用的场景。
方案2:手动管理设备数组生命周期
如果设备数组仅在部分代码段使用,可以不添加device_resident声明,直接通过!$acc enter data create语句指定长度创建设备数组,使用结束后用!$acc exit data delete释放设备内存,全程同样不需要在主机端分配数组。
示例代码如下:
program test implicit none integer, parameter :: n = 1000 real :: total real, allocatable :: array(:) real, allocatable :: array_d(:) allocate(array(n)) ! 无需在主机端分配array_d内存 array(:) = 1e0 ! 手动创建设备端array_d,指定数组长度 !$acc enter data create(array_d(n)) !$acc data copy(array) copyout(total) !$acc kernels array_d(:) = array(:) !$acc end kernels !$acc kernels total = sum(array_d) !$acc end kernels !$acc end data ! 手动释放设备端array_d占用的内存 !$acc exit data delete(array_d) print *, sum(array) print *, total deallocate(array) end program
该方案可以更灵活地控制设备内存的占用,适合大数组临时使用的场景。
注意事项
- 以上功能需要编译器支持至少OpenACC 2.5标准,目前NVIDIA HPC SDK、GCC 10及以上版本均已兼容。
- 仅设备分配的数组严禁在主机端直接读写,否则会触发内存访问错误。
内容的提问来源于stack exchange,提问作者Neraste
相关产品推荐
相关产品推荐

