OpenACC-Fortran顺序调用GPU子例程的技术问题咨询
OpenACC 问题解答
问题1:present子句无法找到GPU端eta的原因
不是必须回传主机再拷贝,核心是**main_function执行完后,编译器可能隐式释放了eta的设备内存**:
- 如果
main_function里的GPU计算区域用!$acc parallel/!$acc kernels且未显式保留设备数据,编译器会在区域结束后自动回传主机数据并释放设备端内存,导致后续present子句找不到设备上的eta。 - 解决方式:在
main_function开头给eta加!$acc enter data显式分配设备内存,计算时用!$acc ... present(eta),结束后不执行!$acc exit data(保留设备数据);也可在main_function的并行区域用!$acc data create(eta)维持数据域到后续使用。同时要确保function_a等子例程正确使用present(eta),避免修改隐式拷贝的副本。
问题2:确保interpolate3D在GPU执行的方法
!$acc routine seq仅声明该子例程可被GPU区域调用,无法单独保证GPU执行:
- 必须将
interpolate3D的调用包裹在OpenACC GPU执行区域内,比如!$acc parallel/!$acc serial/!$acc kernels块中。 - 无循环时的正确写法示例:
同时要确保!$acc serial present(eta, x, y, z, fAtxyz) call interpolate3D(eta, x, y, z, fAtxyz) !$acc end serialeta等数据已通过enter data或之前的并行区域保留在GPU上。
问题3:无循环时需update self(eta)才正确的原因
是的,这说明此时interpolate3D在CPU上执行:
- 未被OpenACC区域包裹的子例程调用默认在CPU执行,CPU只能访问主机端的
eta副本。而main_function计算的eta仅存在于GPU端,主机端是旧数据,因此必须用!$acc update self(eta)将GPU最新数据回传主机,CPU才能拿到正确值计算。
问题4:两步GPU计算的正确实现流程
核心是全程维护eta的设备内存存在性,具体步骤:
第一步:计算并保留GPU端
eta- 在主程序或
main_function入口,显式为eta分配设备内存:!$acc enter data create(eta) - 在
main_function的条件分支中,每个GPU子例程(function_a等)的计算区域标注present(eta),确保修改设备端数据:subroutine function_a(eta, ...) !$acc routine vector !$acc parallel loop present(eta, ...) do ... eta(...) = ... end do !$acc end parallel loop end subroutine main_function结束后不执行!$acc exit data,保留设备端eta。
- 在主程序或
第二步:GPU端使用
eta计算- 将第二个子例程的调用放在OpenACC GPU区域内,用
present(eta)确保访问设备数据:!$acc parallel loop present(eta, input_data, output_data) do i = 1, N call second_routine(eta, input_data(i), output_data(i)) end do !$acc end parallel loop - 给
second_routine添加!$acc routine seq或!$acc routine vector(根据并行性需求),声明其可在GPU执行。
- 将第二个子例程的调用放在OpenACC GPU区域内,用
最终清理
- 所有GPU计算完成后,释放设备内存:
!$acc exit data delete(eta)
- 所有GPU计算完成后,释放设备内存:
内容的提问来源于stack exchange,提问作者FeyPhys
相关产品推荐
相关产品推荐

