OpenACC+MPI Fortran多GPU并行程序开发入门问题咨询
MPI+OpenACC Fortran开发入门问题解答
1. 编译环境配置要求
- 你正在使用的Nvidia HPC-SDK已经内置了适配nvfortran的定制版MPI实现,不需要额外安装其他第三方MPI库,安装SDK时勾选MPI组件即可
- 额外要求:确保所有节点的GPU驱动版本和HPC-SDK版本匹配,避免运行时接口不兼容;如果使用多节点集群,需要集群配置InfiniBand/RoCE这类高速网络,才能启用GPU直接通信特性
- 不需要额外配置其他工具链,全程使用HPC-SDK自带的nvfortran和MPI编译包装器即可
2. 编译方法及Makefile示例
- 不需要分开编译两次,HPC-SDK的MPI编译包装器已经默认适配nvfortran,只要在编译参数里同时加入MPI和OpenACC的对应flag即可
- 基础编译命令示例:
其中mpif90 -acc=gpu -gpu=ccXX,managed -Minfo=accel -O2 your_code.f90 -o mpi_acc_testccXX需要替换为目标GPU的算力,例如A100为cc80,V100为cc70,RTX30系为cc86,RTX40系为cc89;managed参数用于开启统一内存,入门阶段可以省去大量显式数据拷贝的代码 - 极简Makefile示例:
# 编译器直接使用HPC-SDK自带的mpif90包装器 FC = mpif90 # 编译参数:开启OpenACC、指定GPU算力、输出加速信息、开启优化 FFLAGS = -acc=gpu -gpu=cc80,managed -Minfo=accel -O2 # 链接参数,无额外依赖可留空 LDFLAGS = TARGET = mpi_acc_demo OBJS = main.o utils.o all: $(TARGET) $(TARGET): $(OBJS) $(FC) $(FFLAGS) $(OBJS) -o $@ $(LDFLAGS) %.o: %.f90 $(FC) $(FFLAGS) -c $< -o $@ clean: rm -f *.o *.mod $(TARGET) - 运行命令示例:单节点2卡运行直接执行
mpirun -np 2 ./mpi_acc_demo,多节点场景使用集群对应的srun/mpirun调度命令即可
3. 多GPU之间的通信规则
- 支持直接设备通信,也就是GPUDirect RDMA技术,不需要走CPU中转
- 触发直接通信的前提:两个GPU要么在同一节点下通过PCIe/NVLink互联,要么跨节点时集群配置了支持GPUDirect的InfiniBand/RoCE高速网卡;同时通信缓冲区是直接在GPU设备上分配的内存,MPI可以自动识别地址类型,自动选择最优传输路径
- 不满足上述条件时,才会默认走「GPU1拷回主机1→主机1传输到主机2→主机2拷到GPU2」的中转路径
4. Fortran示例代码参考
以下是极简的多卡向量加示例,逻辑为每个MPI进程绑定一块GPU,各计算部分向量后归约结果:
program mpi_acc_vector_add use mpi use openacc implicit none integer :: ierr, rank, size, i integer, parameter :: N = 1000000 real :: a(N), b(N), c(N), local_sum, total_sum integer :: local_N, start_idx, end_idx ! MPI初始化 call MPI_Init(ierr) call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr) call MPI_Comm_size(MPI_COMM_WORLD, size, ierr) ! 关键步骤:每个进程绑定对应rank的GPU call acc_set_device_num(rank, acc_device_nvidia) ! 切分计算任务 local_N = N / size start_idx = rank * local_N + 1 end_idx = (rank + 1) * local_N if (rank == size - 1) end_idx = N ! 0号进程初始化数组 if (rank == 0) then do i = 1, N a(i) = i * 1.0 b(i) = i * 2.0 end do end if ! 分发数据到各进程 call MPI_Scatter(a, local_N, MPI_REAL, a(start_idx), local_N, MPI_REAL, 0, MPI_COMM_WORLD, ierr) call MPI_Scatter(b, local_N, MPI_REAL, b(start_idx), local_N, MPI_REAL, 0, MPI_COMM_WORLD, ierr) ! OpenACC并行计算向量加 !$acc parallel loop copyin(a(start_idx:end_idx), b(start_idx:end_idx)) copyout(c(start_idx:end_idx)) do i = start_idx, end_idx c(i) = a(i) + b(i) end do !$acc end parallel loop ! 计算本地段和 local_sum = 0.0 !$acc parallel loop reduction(+:local_sum) do i = start_idx, end_idx local_sum = local_sum + c(i) end do !$acc end parallel loop ! 归约所有进程的结果到0号进程,MPI自动识别设备地址走GPUDirect call MPI_Reduce(local_sum, total_sum, 1, MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD, ierr) if (rank == 0) then print *, "向量c的总和为: ", total_sum end if call MPI_Finalize(ierr) end program mpi_acc_vector_add
内容的提问来源于stack exchange,提问作者Dumbledore Albus
相关产品推荐
相关产品推荐

