You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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_test
    
    其中ccXX需要替换为目标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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 07:24:05