菜鸟科技网

MPI命令如何高效并行执行任务?

MPI 本身不是一个单一的命令,而是一个标准和一个库,我们通常使用 MPI 实现提供的命令行工具来编译、运行和管理 MPI 程序,最流行的 MPI 实现是 Open MPIMPICH,它们的命令非常相似。

MPI命令如何高效并行执行任务?-图1
(图片来源网络,侵删)

下面我将从核心命令、编译、运行、调试等多个方面进行介绍。


核心运行命令

这是使用 MPI 最核心、最常用的命令,用于启动并行程序。

mpirun

这是最传统、最通用的命令,用于启动 MPI 程序。

基本语法:

MPI命令如何高效并行执行任务?-图2
(图片来源网络,侵删)
mpirun [选项] 程序路径 [程序参数]

常用选项:

  • -n <进程数>--np <进程数>

    • 作用: 指定要启动的 MPI 进程总数,这是最重要的选项。
    • 示例: 启动 4 个进程运行 my_program.exe
      mpirun -n 4 ./my_program.exe
  • -host <主机列表>--host <主机列表>

    • 作用: 指定在哪些主机上运行进程,多个主机用逗号分隔。
    • 示例: 在 node01node02 上各运行 2 个进程(总共 4 个)。
      mpirun -n 4 -host node01,node02 ./my_program.exe
  • -hostfile <主机文件>

    MPI命令如何高效并行执行任务?-图3
    (图片来源网络,侵删)
    • 作用: 指定一个包含主机列表和每个主机可用进程数的文件,这是在集群上作业调度系统(如 Slurm, PBS)中非常常用的方式。
    • 示例: 假设有一个 hostfile 文件,内容如下:
      node01 slots=4
      node02 slots=4

      这表示 node01node02 各自最多可以运行 4 个进程,运行命令如下:

      mpirun -hostfile hostfile ./my_program.exe

      如果不指定 -n,它会尝试使用所有 slots

  • -ppn <每节点进程数>--pernode <每节点进程数>

    • 作用: 指定在每个计算节点上运行的进程数。
    • 示例: 在 2 个节点上运行,每个节点 4 个进程(总共 8 个)。
      mpirun -n 8 -ppn 4 -host node01,node02 ./my_program.exe
  • -bind-to <绑定策略>

    • 作用: 控制 MPI 进程与 CPU 核心的绑定,对性能优化至关重要。
    • 常用值: core (绑定到单个核心), socket (绑定到单个 CPU 插槽), none (不绑定)。
    • 示例: 将每个进程绑定到一个 CPU 核心。
      mpirun -n 4 --bind-to core ./my_program.exe
  • -map-by <映射策略>

    • 作用: 与 bind-to 配合使用,控制进程如何分配到硬件资源。
    • 常用值: core (按核心映射), socket (按插槽映射)。
    • 示例: 按核心映射并绑定。
      mpirun -n 4 --map-by core --bind-to core ./my_program.exe
  • -x <环境变量>

    • 作用: 将指定的环境变量传递给所有 MPI 进程。
    • 示例: 将 PATHMY_APP_CONFIG 传递给所有子进程。
      mpirun -n 4 -x PATH -x MY_APP_CONFIG ./my_program.exe

mpiexec

这是 MPI 标准推荐的命令,功能与 mpirun 基本相同,是更现代的替代品,在很多实现中,mpiexecmpirun 是指向同一个程序的符号链接。

基本语法:

mpiexec [选项] 程序路径 [程序参数]

选项与 mpirun 高度兼容,只是命令名不同。

# 使用 mpiexec 启动 4 个进程
mpiexec -n 4 ./my_program.exe
# 使用主机文件
mpiexec -hostfile hostfile ./my_program.exe

使用建议:

  • 两者功能几乎一样,可以混用。
  • 在一些新的 HPC 系统和文档中,mpiexec 更为常见。
  • 如果不确定,优先使用 mpiexec

编译命令

要编译 MPI 程序,你需要使用 MPI 提供的包装器编译器,它们会自动帮你链接 MPI 库和头文件。

mpicc (用于 C/C++ 程序)

基本语法:

mpicc [选项] 源文件列表 -o 输出文件

示例:

# 编译一个名为 main.c 的 C 程序,生成可执行文件 my_mpi_app
mpicc main.c -o my_mpi_app
# 编译一个包含 MPI 的 C++ 程序 (使用 mpicxx)
mpicxx main.cpp -o my_mpi_app_cpp

mpifortmpif90 (用于 Fortran 程序)

基本语法:

mpifort [选项] 源文件列表 -o 输出文件

示例:

# 编译一个名为 main.f90 的 Fortran 90 程序
mpifort main.f90 -o my_fortran_app

包装器编译器的优势:

  • 自动链接: 无需手动查找 MPI 库路径和库名称。
  • 跨平台兼容性: 不同安装的 MPI,其库路径和名称可能不同,包装器能自动处理。
  • 编译器标志: 会根据底层 C/Fortran 编译器(如 GCC, Intel)传递合适的标志。

调试与分析命令

mpirun / mpiexec 内置调试

  • --mca <组件名> <参数>: 修改 MPI 内部组件的参数。btl (Byte Transfer Layer) 是最常用的组件之一,用于控制网络通信。
    • 示例: 禁用 TCP 通信,强制使用 InfiniBand (如果可用),这有时可以解决网络问题或提高性能。
      mpirun -n 4 --mca btl ^open,self,sm ./my_program.exe

      ^ 表示从列表中移除,这个例子表示禁用 open, self, sm 之外的 BTL,通常意味着只使用 tcp,但更常见的用法是禁用 tcp 来强制使用高性能网络。

mpiexec.hydrampirun.hydra

mpirun 的底层实现是 orted(守护进程)和 orterun(用户端程序),在较新的 Open MPI 版本中,用户端程序通常叫 hydra,你可以直接调用它来获得更细粒度的控制。

  • --debug-devel: 输出非常详细的调试信息(仅用于开发)。
  • --verbose: 输出更详细的启动信息。

外部调试器集成

要使用 GDB 等调试器调试 MPI 程序,需要附加到正在运行的 MPI 进程上。

  • 步骤:

    1. 启动 MPI 程序,并获取其进程 ID (PID),通常使用 mpirun--prefix 选项或 --xterm 选项来启动调试器。
    2. 在一个终端中,使用 ps 命令找到 MPI 程序的 PID。
    3. 在另一个终端中,使用 gdb --pid=<PID> 附加到进程。
  • 使用 xterm 启动 (方便但繁琐):

    # 这会为每个进程打开一个 xterm 窗口,然后在每个窗口中启动 gdb
    mpirun --xterm -n 4 ./my_program.exe

    然后在每个 xterm 窗口中手动输入 gdb attach <pid>

  • 更现代的方法 (推荐): 使用 TotalView 等专业的并行调试器,它们能更好地与 MPI 集成。

性能分析工具

  • mpirun -mca pml ob1 -mca btl self,vader,sm ...: 通过选择不同的 pml (进程管理层) 和 btl (字节传输层) 组件,可以分析不同通信库和驱动对性能的影响。
  • 外部工具:
    • mpirun -np 4 valgrind --tool=memcheck ./my_program.exe: 使用 Valgrind 检测内存泄漏。
    • mpirun -np 4 ./my_program.exe + mpiP: mpiP 是一个 MPI 性能剖析工具,需要重新编译 MPI 并使用其特殊包装器。

总结与最佳实践

场景 命令示例 说明
编译 C 程序 mpicc main.c -o my_app 使用 MPI 包装器编译器
编译 Fortran 程序 mpifort main.f90 -o my_app 使用 MPI 包装器编译器
在单机上运行 mpirun -n 4 ./my_app 启动 4 个进程,默认使用所有可用核心
在集群上运行 mpirun -hostfile my_hosts -n 16 ./my_app 使用主机文件,启动 16 个进程
绑定进程到核心 mpirun -n 4 --bind-to core --map-by core ./my_app 优化性能,避免进程在核心间迁移
传递环境变量 mpirun -n 4 -x LD_LIBRARY_PATH ./my_app 确保子进程能找到所需的动态库
使用调试器 mpirun --xterm -n 4 ./my_app 为每个进程打开一个终端用于调试
查看帮助 mpirun --help 查看所有可用选项

核心要点:

  1. 编译用 mpicc/mpifort: 不要直接用 gcc/gfortran,除非你非常清楚如何手动链接 MPI。
  2. 运行用 mpirunmpiexec: -n 是指定进程数的关键。
  3. 集群环境用 -hostfile: 这是与作业调度系统交互的标准方式。
  4. 性能优化靠绑定: 使用 --bind-to--map-by 来优化进程与 CPU 的亲和性,对多节点、多 NUMA 节点的系统尤其重要。
  5. 善用 --help: MPI 的选项非常多,mpirun --help 是你最好的朋友。

希望这份详细的指南能帮助你更好地使用 MPI 命令!

分享:
扫描分享到社交APP
上一篇
下一篇