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

下面我将从核心命令、编译、运行、调试等多个方面进行介绍。
核心运行命令
这是使用 MPI 最核心、最常用的命令,用于启动并行程序。
mpirun
这是最传统、最通用的命令,用于启动 MPI 程序。
基本语法:

mpirun [选项] 程序路径 [程序参数]
常用选项:
-
-n <进程数>或--np <进程数>- 作用: 指定要启动的 MPI 进程总数,这是最重要的选项。
- 示例: 启动 4 个进程运行
my_program.exe。mpirun -n 4 ./my_program.exe
-
-host <主机列表>或--host <主机列表>- 作用: 指定在哪些主机上运行进程,多个主机用逗号分隔。
- 示例: 在
node01和node02上各运行 2 个进程(总共 4 个)。mpirun -n 4 -host node01,node02 ./my_program.exe
-
-hostfile <主机文件>
(图片来源网络,侵删)- 作用: 指定一个包含主机列表和每个主机可用进程数的文件,这是在集群上作业调度系统(如 Slurm, PBS)中非常常用的方式。
- 示例: 假设有一个
hostfile文件,内容如下:node01 slots=4 node02 slots=4这表示
node01和node02各自最多可以运行 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 进程。
- 示例: 将
PATH和MY_APP_CONFIG传递给所有子进程。mpirun -n 4 -x PATH -x MY_APP_CONFIG ./my_program.exe
mpiexec
这是 MPI 标准推荐的命令,功能与 mpirun 基本相同,是更现代的替代品,在很多实现中,mpiexec 和 mpirun 是指向同一个程序的符号链接。
基本语法:
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
mpifort 或 mpif90 (用于 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来强制使用高性能网络。
- 示例: 禁用 TCP 通信,强制使用 InfiniBand (如果可用),这有时可以解决网络问题或提高性能。
mpiexec.hydra 或 mpirun.hydra
mpirun 的底层实现是 orted(守护进程)和 orterun(用户端程序),在较新的 Open MPI 版本中,用户端程序通常叫 hydra,你可以直接调用它来获得更细粒度的控制。
--debug-devel: 输出非常详细的调试信息(仅用于开发)。--verbose: 输出更详细的启动信息。
外部调试器集成
要使用 GDB 等调试器调试 MPI 程序,需要附加到正在运行的 MPI 进程上。
-
步骤:
- 启动 MPI 程序,并获取其进程 ID (PID),通常使用
mpirun的--prefix选项或--xterm选项来启动调试器。 - 在一个终端中,使用
ps命令找到 MPI 程序的 PID。 - 在另一个终端中,使用
gdb --pid=<PID>附加到进程。
- 启动 MPI 程序,并获取其进程 ID (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 |
查看所有可用选项 |
核心要点:
- 编译用
mpicc/mpifort: 不要直接用gcc/gfortran,除非你非常清楚如何手动链接 MPI。 - 运行用
mpirun或mpiexec:-n是指定进程数的关键。 - 集群环境用
-hostfile: 这是与作业调度系统交互的标准方式。 - 性能优化靠绑定: 使用
--bind-to和--map-by来优化进程与 CPU 的亲和性,对多节点、多 NUMA 节点的系统尤其重要。 - 善用
--help: MPI 的选项非常多,mpirun --help是你最好的朋友。
希望这份详细的指南能帮助你更好地使用 MPI 命令!
