我们来深入浅出地讲解 mpirun(以及其同义词如 mpiexec, orterun)的运行原理。

mpirun 是 MPI(消息传递接口)实现(如 Open MPI, MPICH, Intel MPI)提供的一个命令行工具,它的核心任务非常简单:启动一个并行作业,并在指定的多个计算节点上创建和管理多个进程,让这些进程能够通过 MPI 库进行通信。

它的运行原理可以分解为以下几个关键阶段和组件:

核心思想:一个“管理器-工作者”模型

可以把 mpirun 进程本身看作一个 “管理器” ,而它启动的 MPI 进程则是 “工作者”


1. 解析命令行参数和主机信息

当你执行类似下面的命令时:

bash

mpirun -n 4 -host node1,node2,node3,node4 ./my_mpi_program

mpirun 首先会:

  • 解析参数:知道要启动 4 个进程 (-n 4)。

  • 构建主机列表:知道要在 node1, node2, node3, node4 这四个节点上运行。

  • 定位程序:找到可执行文件 ./my_mpi_program


2. 启动基础运行环境

这是最关键的一步。mpirun 本身是 MPI 实现中一个叫做 ORTE (Open Run-Time Environment)PMI (Process Management Interface) 的前端。

  • ORTE: 是 Open MPI 使用的运行时环境。

  • PMI: 是 MPICH 及其衍生版本(如 Intel MPI)使用的进程管理接口。

这个运行时环境负责所有底层的进程管理、通信和资源管理的脏活累活。

具体启动流程如下:

  1. 启动“头节点”上的守护进程

    • mpirun 首先会在你运行命令的那个节点(头节点) 上启动一个高级别的管理器进程,通常称为 orted(ORTE 守护进程)或 hydra_pmi_proxy(对于 MPICH-Hydra)。

    • 这个 orted 是全局的“总指挥”。

  2. 在远程节点上启动守护进程

    • 然后,总指挥 orted 会通过某种远程启动机制(如 SSH、RSH 或专门的资源管理器如 Slurm/PBS 提供的接口)连接到主机列表中的其他节点(node2, node3, node4)。

    • 在每个远程节点上,它都会启动一个对应的 orted 守护进程。这些远程的 orted 是“分指挥”。

  3. 形成通信网络

    • 现在,所有节点上的 orted 守护进程会相互建立连接,形成一个内部的管理网络。这个网络独立于 MPI 进程间用于数据传输的数据网络(如 InfiniBand, Ethernet)。


3. 启动 MPI 进程

管理网络建立好后,真正的 MPI 进程启动开始了:

  1. 总指挥分发任务:头节点的 mpirun 通过管理网络向所有 orted(包括本地的和远程的)发送命令:“在你的节点上,启动 N 个 my_mpi_program 进程”。

  2. 分指挥执行:每个节点上的 orted 守护进程接收到命令后,fork()exec() 出指定数量的 MPI 进程。

  3. 设置环境:在启动每个 MPI 进程时,orted 会为其设置关键的环境变量,最重要的是:

    • PMI_FD: 一个文件描述符,用于与 orted 通信。

    • 或者其他类似的通信通道标识符。


4. 信息交换与建立通信域

这是 MPI 魔法发生的地方。每个 MPI 进程启动后,它需要知道:

  • “我是谁?”(我的进程编号 MPI_Rank

  • “总共有多少人?”(通信域大小 MPI_Comm_size

  • “如何联系到其他人?”(其他进程的地址信息)

这个过程是通过 PMI(Process Management Interface)PRRTE(PMIx Reference RunTime Environment) 来完成的。

  1. MPI 进程联系本地守护进程:每个 MPI 进程启动后,会通过 PMI_FD 这个“管道”与本节点orted 守护进程进行通信。这是一个本地通信,非常高效。

  2. 信息收集:MPI 进程向 orted 注册自己,并询问初始化信息。

  3. 信息交换:所有节点上的 orted 通过它们之间的管理网络,交换所有 MPI 进程的联系信息(例如:IP地址、端口号、用于高速网络的硬件地址等)。

  4. 信息分发:一旦 orted 收集齐了所有信息,它就会通过 PMI_FD 将完整的“通讯录”(包含所有进程的地址和排名)分发给它管理的每一个 MPI 进程。

  5. 建立连接:MPI 进程拿到“通讯录”后,彼此之间会建立 TCP 连接或利用 RDMA(远程直接内存访问)等技术建立高速网络连接,形成 MPI 的通信域(如 MPI_COMM_WORLD)。


5. 运行与监控

  • 执行用户代码:此时,所有 MPI 进程开始执行 my_mpi_program 中的 main 函数,并进行消息传递。

  • 标准 I/O 管理:默认情况下,所有 MPI 进程的 stdoutstderr 都会被重定向回 mpirun,这就是为什么你能在同一个终端上看到所有进程的输出(虽然可能是乱序的)。你可以使用 -output-filename 等选项改变这一行为。

  • 信号处理和监控mpirunorted 会监控 MPI 进程的状态。如果一个进程异常退出(例如 Segmentation Fault),管理器会终止所有其他进程。当你按下 Ctrl+C 时,信号也会被传播给所有 MPI 进程。


6. 终止与清理

  • 当所有 MPI 进程正常退出后,它们会通知本地的 orted

  • orted 然后通知头节点的总指挥。

  • 总指挥会命令所有 orted 自行退出。

  • 最后,mpirun 本身退出,返回一个适当的退出码。

总结与类比

组件 角色 类比
mpirun 总司令 公司的CEO,制定总体战略(命令行参数)。
orted 经理层 公司的中层经理(本地和远程)。他们听从CEO,管理基层员工。
MPI 进程 工作者 公司的基层员工,负责具体工作(执行计算)。他们只和直属经理打交道。
管理网络 内部管理通道 经理之间的电话会议/内部邮件系统。
数据网络 工作协作通道 员工之间为了完成项目而进行的直接沟通和文件传输。
PMI 工作流程接口 员工向经理汇报工作和获取资源的标准化流程(如申请办公用品、获取同事联系方式)。

现代环境的补充:与作业调度器集成

在高性能计算集群中,你通常不会直接在所有节点上 SSH,而是通过作业调度器(如 Slurm, PBS/Torque)来提交作业。

在这种情况下,mpirun 的工作会大大简化:

  • 你通过 sbatch(Slurm)提交一个作业脚本。

  • Slurm 的 srun 负责在所有分配的计算节点上启动任务。

  • 在作业脚本中调用 mpirun 时,mpirun自动检测到它正在 Slurm 环境中运行。

  • 于是,mpirun 不再使用 SSH,而是直接调用 Slurm 的接口(例如通过 PMI-2)来启动和管理 MPI 进程。Slurm 自身扮演了“总指挥”和“分指挥”的角色。

所以,现代 mpirun 的原理是:作为一个灵活的包装器,根据当前环境(直接SSH、Slurm、PBS等)选择合适的底层启动机制(ORTE, PMI等),以高效地完成分布式进程的启动、初始化和管理工作。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐