【发布时间】:2018-05-24 09:57:55
【问题描述】:
上下文:
整个问题可以概括为我正在尝试复制对system(或fork)的调用行为,但在mpi 环境中。 (事实证明你不能并行调用system。)这意味着我有一个程序在许多节点上运行,每个节点上有一个进程,然后我希望每个进程调用一个外部程序(所以对于n 节点我会运行外部程序的n 副本),等待所有这些副本完成,然后继续运行原始程序。
为了以一种在并行环境中安全的方式实现这一点,我一直在使用MPI_COMM_SPAWN 和阻塞发送的组合。以下是我实现的一些示例父子程序(代码在 Fortran 90 中,但 C 程序的语法类似):
父.f90:
program parent
include 'mpif.h'
!usual mpi variables
integer :: size, rank, ierr
integer :: status(MPI_STATUS_SIZE)
integer MPI_COMM_CHILD, ri
integer tag
character *128 message
call MPI_Init(ierr)
call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
write(*, *) "I am parent on rank", rank, "of", size
call MPI_COMM_SPAWN('./child', MPI_ARGV_NULL, 1, MPI_INFO_NULL, 0, &
MPI_COMM_SELF, MPI_COMM_CHILD, MPI_ERRCODES_IGNORE, ierr)
write(*, *) "Parent", MPI_COMM_SELF, "child comm", MPI_COMM_CHILD
tag = 1
call MPI_RECV(message, 128, MPI_CHARACTER, 0, tag, MPI_COMM_CHILD,&
status, ierr)
write(*, *) "Parent", MPI_COMM_SELF, "child comm", MPI_COMM_CHILD,&
"!!!"//trim(message)//"!!!"
call mpi_barrier(mpi_comm_world, ierr)
call MPI_Finalize(ierr)
end program parent
child.f90:
program child
include 'mpif.h'
!usual mpi variables
integer :: size, rank, ierr, parent
integer :: status(MPI_STATUS_SIZE)
integer MPI_COMM_PARENT, psize, prank
integer tag
character *128 message
call MPI_init(ierr)
call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
call MPI_Comm_get_parent(MPI_COMM_PARENT)
call MPI_Comm_size(MPI_COMM_PARENT, psize, ierr)
call MPI_Comm_rank(MPI_COMM_PARENT, prank, ierr)
write(*, *) "I am child on rank", rank, "of", size, "with comm",&
MPI_COMM_WORLD, "and parent", MPI_COMM_PARENT,&
psize, prank
tag = 1
message = 'Hello Mom and/or Dad!'
call MPI_SEND(message, 128, MPI_CHARACTER, 0, tag, MPI_COMM_PARENT, ierr)
call mpi_barrier(MPI_COMM_WORLD, ierr)
call MPI_Finalize(ierr)
end program child
使用 ifort 16.0.3 和 intel openmpi 1.10.3 编译并使用(例如)mpirun -np 4 ./parent 运行后,我得到以下输出:
I am parent on rank 0 of 4
I am parent on rank 1 of 4
I am parent on rank 2 of 4
I am parent on rank 3 of 4
Parent 1 child comm 3
I am child on rank 0 of 1 with comm 0 and parent
3 1 0
Parent 1 child comm 3 !!!Hello Mom and/or Dad!!!!
Parent 1 child comm 3
I am child on rank 0 of 1 with comm 0 and parent
3 1 0
Parent 1 child comm 3
I am child on rank 0 of 1 with comm 0 and parent
3 1 0
Parent 1 child comm 3 !!!Hello Mom and/or Dad!!!!
Parent 1 child comm 3 !!!Hello Mom and/or Dad!!!!
Parent 1 child comm 3
I am child on rank 0 of 1 with comm 0 and parent
3 1 0
Parent 1 child comm 3 !!!Hello Mom and/or Dad!!!!
这本质上是我想要的行为。据我了解,通过使用maxprocs=1、root=0 和MPI_COMM_SELF 作为父通信器,我告诉每个父进程生成一个只知道其父进程的子进程,因为它是root=0( MPI_COMM_SELF 范围的唯一进程)。然后我要求它等待来自其子进程的消息。孩子获得父母的(SELF)通信器并将其消息发送到只能是父母的root=0。所以这一切都很好。
问题:
我希望每个进程都会在自己的节点上生成子进程。我运行的 mpi 进程数等于节点数,当我调用 mpirun 时,我使用标志 --map-by node 来确保每个节点一个进程。我希望子进程会以某种方式继承它,否则不知道是否存在任何其他节点。但是我看到的行为是非常不可预测的,一些进程跨节点传播,而其他节点(尤其是主 mpi 进程的root=0)会堆积很多。
有没有办法确保进程绑定到父进程的节点?也许通过我可以传递给MPI_COMM_SPAWN 的MPI_Info 选项?
【问题讨论】:
-
对于所有 Fortran 问题,请使用标签 fortran。您的问题并非针对旧的和过时的 Fortran 90。请注意,使用
use mpi而不是include "mpif.h"可以帮助您诊断某些类型的错误。
标签: c parallel-processing fortran mpi openmpi