如何在OpenACC内核中转换Fortran的move_alloc内置函数?
在OpenACC GPU环境下迁移可分配数组的动态扩容逻辑
OpenACC设备端内核不支持直接调用move_alloc——这个内置函数是主机端的内存操作接口,无法在GPU上执行。要实现主机端那种高效的无拷贝扩容,需要通过主机端协调设备内存的关联与管理,具体步骤如下:
核心思路
主机端主导设备内存的分配、数据拷贝和关联转移,内核仅负责数据的填充与拷贝操作,避免不必要的主机-设备数据传输。
具体实现步骤
假设你已经有一个包含可分配数组的Fortran结构体,且该结构体的数组已通过OpenACC指令卸载到GPU:
type :: my_data integer, allocatable :: arr(:) end type my_data type(my_data) :: gpu_struct
在设备端创建新的临时数组
在主机端用!$acc enter data create指令直接在GPU上分配指定大小的临时数组tmp,跳过主机端分配再拷贝的步骤:integer, allocatable :: tmp(:) integer, parameter :: new_size = 200 ! 目标扩容大小 !$acc enter data create(tmp(new_size))内核中完成数据迁移与补0
启动OpenACC内核,将原数组的有效数据拷贝到tmp,并对新增区域补0:integer :: old_size, i old_size = size(gpu_struct%arr) ! 拷贝原有数据 !$acc parallel loop present(gpu_struct%arr, tmp) do i = 1, min(old_size, new_size) tmp(i) = gpu_struct%arr(i) end do !$acc end parallel loop ! 对新增区域补0(如果新尺寸大于原尺寸) if (new_size > old_size) then !$acc parallel loop present(tmp) do i = old_size + 1, new_size tmp(i) = 0 end do !$acc end parallel loop end if主机端完成内存关联转移
先在主机端用move_alloc完成主机数组的无拷贝替换,再通过OpenACC指令将设备端的tmp内存关联到结构体的数组上,同时清理旧的设备内存:! 主机端替换数组,tmp会被自动释放(主机端) call move_alloc(tmp, gpu_struct%arr) ! 删除设备端原有的旧数组内存(确保无其他引用) !$acc exit data delete(gpu_struct%arr) ! 将设备端的tmp内存与新的gpu_struct%arr关联 !$acc attach(gpu_struct%arr)
关键注意事项
- 避免设备端内存操作:所有内存分配、释放、关联操作必须在主机端执行,内核仅处理数据计算/拷贝。
attach指令的作用:attach不会重新分配设备内存,而是将主机端的可分配数组与已存在的设备内存绑定,实现类似move_alloc的无拷贝转移效果。- 内存安全:执行
exit data delete前,必须确保旧的设备数组没有被其他内核或数据结构引用,否则会导致内存访问错误。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

