串行调用mpi二进制文件作为mpi应用程序的子进程

时间:2014-01-13 11:24:45

标签: python c parallel-processing mpi

我有一个大型并行(使用MPI)模拟应用程序,它可以生成大量数据。为了评估这些数据,我使用了一个python脚本。

我现在需要做的是多次运行此应用程序(> 1000)并从结果数据中计算统计属性。

到目前为止,我的方法是让一个python脚本并行运行(使用mpi4py,使用48个节点),使用subprocess.check_call调用模拟代码。 我需要这个调用来串行运行我的mpi模拟应用程序。 在这种情况下,我不需要模拟并行运行。 然后python脚本可以并行分析数据,完成后将启动一个新的模拟运行,直到累积大量的运行。

目标是

  • 未保存2000次运行的整个数据集
  • 将中间数据保存在内存中

Stub MWE:

档案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 1srun进行子进程调用无效

有没有优雅,官方的方式这样做?我真的没有想法,感谢任何意见!

1 个答案:

答案 0 :(得分:6)

不,既没有优雅也没有官方的方式来做到这一点。从MPI应用程序中执行其他程序的唯一官方支持的方法是使用MPI_Comm_spawn。通过subprocess提供的简单操作系统机制产生子MPI进程是危险,在某些情况下甚至可能产生灾难性后果。

虽然MPI_Comm_spawn没有提供查找子进程何时退出的机制,但您可以使用intercomm barrier来模拟它。您仍然会遇到问题,因为MPI_Comm_spawn调用不允许任意重定向标准I / O,而是将其重定向到mpiexec / mpirun

您可以做的是编写一个包装脚本,删除MPI库可能使用的所有可能路径,以便传递会话信息。对于Open MPI,它可以是以OMPI_开头的任何环境变量。对于英特尔MPI,它将是以I_开头的变量。等等。有些库可能会使用文件或共享内存块或其他一些操作系统机制,您也必须处理这些内容。一旦消除了任何可能的通信MPI会话信息的机制,您就可以简单地启动可执行文件,它应该形成一个单独的MPI作业(就像运行mpiexec -n 1一样)。