使用MPI_Comm_spawn时OpenMPI的nooversubscribe机制失效问题
MPI_Comm_spawn子进程分布问题及解决(OpenMPI 4.1.2)
我编写了一个基于MPI_Comm_spawn的代码,目标生成4个子进程并让它们分布在不同节点:
#include <stdio.h> #include <stdlib.h> #include <mpi.h> int main(int argc, char* argv[]){ MPI_Init(&argc, &argv); MPI_Comm intercomm; int final_nranks = 4, len; char name[MPI_MAX_PROCESSOR_NAME]; MPI_Get_processor_name(name, &len); MPI_Comm_get_parent(&intercomm); if(intercomm == MPI_COMM_NULL){ MPI_Info info; MPI_Info_create(&info); MPI_Info_set(info, "hostfile", "hostfile"); MPI_Info_set(info, "pernode", "true"); MPI_Comm_spawn(argv[0], MPI_ARGV_NULL, final_nranks, info, 0, MPI_COMM_WORLD, &intercomm, MPI_ERRCODES_IGNORE); printf("PARENT %s\n", name); } else { printf("CHILD %s\n", name); } MPI_Finalize(); return 0; }
用以下命令启动:
$ mpirun -np 2 --hostfile hostfile --map-by node ./a.out
期望输出是父进程在node00、node01,子进程分布在node00到node03各一个,但实际:
- 添加
MPI_Info_set(info, "pernode", "true");时程序崩溃,报错PML add procs failed等内部错误 - 移除该语句后,所有子进程都集中在同一节点
问题原因分析
pernode参数不合法:OpenMPI的MPI_Comm_spawn支持的MPI_Info参数中并没有pernode,错误设置该参数会导致运行时内部故障,触发初始化失败。- 子进程默认映射策略:默认情况下,OpenMPI会优先将spawn的子进程调度到父进程所在的节点(如果该节点有剩余可用槽位),导致子进程集中在同一节点。
解决方案
1. 修正代码:移除无效参数,添加正确映射策略
删除代码中错误的MPI_Info_set(info, "pernode", "true");,改为设置map-by参数指定子进程按节点分布,同时禁止超额订阅避免进程挤在同一节点:
#include <stdio.h> #include <stdlib.h> #include <mpi.h> int main(int argc, char* argv[]){ MPI_Init(&argc, &argv); MPI_Comm intercomm; int final_nranks = 4, len; char name[MPI_MAX_PROCESSOR_NAME]; MPI_Get_processor_name(name, &len); MPI_Comm_get_parent(&intercomm); if(intercomm == MPI_COMM_NULL){ MPI_Info info; MPI_Info_create(&info); MPI_Info_set(info, "hostfile", "hostfile"); // 设置子进程按节点映射 MPI_Info_set(info, "map-by", "node"); // 禁止超额订阅,确保子进程不会分配到槽位已满的节点 MPI_Info_set(info, "oversubscribe", "false"); MPI_Comm_spawn(argv[0], MPI_ARGV_NULL, final_nranks, info, 0, MPI_COMM_WORLD, &intercomm, MPI_ERRCODES_IGNORE); printf("PARENT %s\n", name); } else { printf("CHILD %s\n", name); } MPI_Finalize(); return 0; }
2. 确保hostfile配置正确
hostfile需要明确每个节点的可用槽位,例如:
node00 slots=1 node01 slots=1 node02 slots=1 node03 slots=1
每个节点仅设置1个槽位,强制OpenMPI将子进程分配到不同节点。
3. 验证结果
修正后运行原启动命令,即可得到期望的输出:
PARENT node00 PARENT node01 CHILD node00 CHILD node01 CHILD node02 CHILD node03
内容的提问来源于stack exchange,提问作者Bub Espinja
相关产品推荐
相关产品推荐

