串行调用mpi二进制文件作为mpi应用程序的子进程
我有一个大型并行(使用MPI)模拟应用程序,它可以生成大量数据。 为了评估这些数据,我使用了一个python脚本。
我现在需要做的是运行此应用程序很多次(> 1000)并从结果数据计算统计属性。
到目前为止,我的方法是让一个python脚本并行运行(使用mpi4py,使用ie节点),使用subprocess.check_call调用模拟代码。 我需要这个调用来串行运行我的mpi模拟应用程序。 在这种情况下,我不需要模拟并行运行。 然后python脚本可以并行分析数据,并在完成后启动新的模拟运行,直到累积大量运行。
目标是
- 不保存2000次运行的整个数据集
- 将中间数据保存在内存中
Stub MWE:
file multi_call_master.py
:
from mpi4py import MPI import subprocess print "Master hello" call_string = 'python multi_call_slave.py' comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() print "rank %d of size %d in master calling: %s" % (rank, size, call_string) std_outfile = "./sm_test.out" nr_samples = 1 for samples in range(0, nr_samples): with open(std_outfile, 'w') as out: subprocess.check_call(call_string, shell=True, stdout=out) # analyze_data() # communicate_results()
file multi_call_slave.py
(这将是C模拟代码):
from mpi4py import MPI print "Slave hello" comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() print "rank %d of size %d in slave" % (rank, size)
这不行。 stdout
产生的结果:
Master hello rank 1 of size 2 in master calling: python multi_call_slave_so.py Master hello rank 0 of size 2 in master calling: python multi_call_slave_so.py [cli_0]: write_line error; fd=7 buf=:cmd=finalize : system msg for write_line failure : Broken pipe Fatal error in MPI_Finalize: Other MPI error, error stack: MPI_Finalize(311).....: MPI_Finalize failed MPI_Finalize(229).....: MPID_Finalize(150)....: MPIDI_PG_Finalize(126): PMI_Finalize failed, error -1 [cli_1]: write_line error; fd=8 buf=:cmd=finalize : system msg for write_line failure : Broken pipe Fatal error in MPI_Finalize: Other MPI error, error stack: MPI_Finalize(311).....: MPI_Finalize failed MPI_Finalize(229).....: MPID_Finalize(150)....: MPIDI_PG_Finalize(126): PMI_Finalize failed, error -1
sm_test.out
结果输出:
Slave hello rank 0 of size 2 in slave
原因是,子进程假定作为并行应用程序运行,而我打算将其作为串行应用程序运行。 作为一个非常“hacky”的解决方法,我做了以下事情:
- 使用特定的mpi分布编译所有需要的mpi感知库,即intel mpi
- 使用不同的mpi库编译模拟代码,即openmpi
如果我现在使用intel mpi启动我的并行python脚本,底层模拟将不会意识到周围的并行环境,因为它使用的是不同的库。
这种方法运行良好一段时间,但不幸的是,由于各种原因,它不是非常便携并且难以在不同的集群上维护。
我可以
- 使用
srun
将子进程调用循环放入shell脚本中- 要求在HD上缓冲结果
- 在python中使用某种
MPI_Comm_spawn
技术- 不应该那样用
- 很难找出子进程是否完成
- 可以更改必要的C代码
- 以某种方式欺骗子进程不转发MPI信息
- 试图操纵环境变量无济于事
- 也不意味着像这样使用
- 使用
mpirun -n 1
或srun
进行子进程调用没有帮助
这有什么优雅,官方的方式吗? 我真的没有想法,感谢任何投入!
不,没有优雅或官方的方式来做到这一点。 从MPI应用程序中执行其他程序的唯一官方支持的方法是使用MPI_Comm_spawn
。 通过简单的OS机制(如subprocess
提供的机制)产生子MPI subprocess
是危险的 ,甚至在某些情况下甚至可能产生灾难性后果。
虽然MPI_Comm_spawn
没有提供查找子进程何时退出的机制,但您可以使用intercomm barrier来模拟它。 您仍然会遇到问题,因为MPI_Comm_spawn
调用不允许任意重定向标准I / O,而是将其重定向到mpiexec
/ mpirun
。
您可以做的是编写一个包装脚本,删除MPI库可能使用的所有可能路径,以便传递会话信息。 对于Open MPI,它可以是以OMPI_
开头的任何环境变量。 对于英特尔MPI,它将是以I_
开头的变量。 等等。 有些库可能会使用文件或共享内存块或其他一些操作系统机制,您也必须处理这些内容。 一旦根除了任何可能的通信MPI会话信息的机制,您就可以简单地启动可执行文件,它应该形成一个单独的MPI作业(就像使用mpiexec -n 1
一样运行)。