串行调用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 1srun进行子进程调用没有帮助

这有什么优雅,官方的方式吗? 我真的没有想法,感谢任何投入!

不,没有优雅或官方的方式来做到这一点。 从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一样运行)。