我正在处理一个MPI应用程序,当它以超过2071个MPI进程启动时挂起。我成功地做到了这一点的小型复制:
program main
use mpi
integer :: ierr,rank
call mpi_init(ierr)
call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
if (rank.eq.0) print *,'Start'
call test_func(ierr)
if (ierr.ne.0) call exit(ierr)
call mpi_finalize(ierr)
if (rank.eq.0) print *,'Stop'
contains
subroutine test_func(ierr)
integer, intent(out) :: ierr
real :: send,recv
integer :: i,j,status(MPI_STATUS_SIZE),mpi_rank,mpi_size,ires
character(len=10) :: procname
real(kind=8) :: t1,t2
ierr=0
call mpi_comm_size(MPI_COMM_WORLD,mpi_size,ierr)
call mpi_comm_rank(MPI_COMM_WORLD,mpi_rank,ierr)
call mpi_get_processor_name(procname, ires, ierr)
call mpi_barrier(MPI_COMM_WORLD,ierr)
t1 = mpi_wtime()
do j=0,mpi_size-1
if (mpi_rank.eq.j) then
do i=0,mpi_size-1
if (i.eq.j) cycle
call MPI_RECV(recv,1,MPI_REAL,i,0,MPI_COMM_WORLD,status,ierr)
if (ierr.ne.0) return
if (i.eq.mpi_size-1) print *,'Rank ',j,procname,' done'
enddo
else
call MPI_SEND(send,1,MPI_REAL,j,0,MPI_COMM_WORLD,ierr)
if (ierr.ne.0) return
endif
enddo
call mpi_barrier(MPI_COMM_WORLD,ierr)
t2 = mpi_wtime()
if (mpi_rank.eq.0) print*,"time send/recv = ",t2-t1
end subroutine test_func
end program main当我用少于2071 MPI进程运行这个程序时,它就工作了,但是当我用超过2072个进程运行它时,它就挂起了,就好像发送/recv上有死锁一样。使用I_MPI_DEBUG=5运行程序的输出是
[0] MPI startup(): Intel(R) MPI Library, Version 2019 Update 9 Build 20200923 (id: abd58e492)
[0] MPI startup(): Copyright (C) 2003-2020 Intel Corporation. All rights reserved.
[0] MPI startup(): library kind: release
[0] MPI startup(): libfabric version: 1.10.1-impi
[0] MPI startup(): libfabric provider: verbs;ofi_rxm
[0] MPI startup(): Rank Pid Node name Pin cpu
[0] MPI startup(): 0 48487 r30i0n0 {0,24}
...
[0] MPI startup(): 2070 34737 r30i4n14 {18,19,20,42,43,44}
[0] MPI startup(): I_MPI_CC=icc
[0] MPI startup(): I_MPI_CXX=icpc
[0] MPI startup(): I_MPI_FC=ifort
[0] MPI startup(): I_MPI_F90=ifort
[0] MPI startup(): I_MPI_F77=ifort
[0] MPI startup(): I_MPI_ROOT=/data_local/sw/intel/RHEL7/compilers_and_libraries_2020.4.304/linux/mpi
[0] MPI startup(): I_MPI_MPIRUN=mpirun
[0] MPI startup(): I_MPI_HYDRA_RMK=lsf
[0] MPI startup(): I_MPI_HYDRA_TOPOLIB=hwloc
[0] MPI startup(): I_MPI_INTERNAL_MEM_POLICY=default
[0] MPI startup(): I_MPI_EXTRA_FILESYSTEM=1
[0] MPI startup(): I_MPI_EXTRA_FILESYSTEM_FORCE=lustre
[0] MPI startup(): I_MPI_DEBUG=5问题1:有理由解释这种行为吗?
请注意,如果我将发送/recv通信模式更改为bcast通信模式之一
do j=0,mpi_size-1
if (mpi_rank.eq.j) then
call MPI_BCAST(send,1,MPI_REAL,j,MPI_COMM_WORLD,ierr)
else
call MPI_BCAST(recv,1,MPI_REAL,j,MPI_COMM_WORLD,ierr)
endif
if (ierr.ne.0) return
print *,'Rank ',j,procname,' done'
enddo或者说是一个
call MPI_ALLGATHER(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,recv,1,MPI_REAL,MPI_COMM_WORLD,ierr)
print *,'Rank ',mpi_rank,procname,' done '然后,程序运行(当然更快),但最多有4000个MPI进程(我没有尝试使用更多的MPI进程)。但是,我不能用bcast或application更改原始应用程序中的通信发送/recv模式。
问题2:当我使用2064个MPI进程(86个节点有24个核心)运行原始应用程序时,MPI缓冲区的消耗内存大约是每个节点60 GB,而对于1032个MPI进程(43个节点有24个核心),每个节点的内存大约为30 GB。有一种方法(环境变量.)要减少消耗的内存量?
非常感谢您的帮助。
蒂埃里
发布于 2022-01-13 19:19:55
我同意前面的意见,似乎您在单个进程上启动了太多的recv,而MPI实现可能会耗尽某些内部缓冲区。
不过,我不建议使用Ssend或引入障碍。只需用MPI_Irecv替换所有的MPI_Recv,用MPI_Isend替换MPI_Send的MPI_Send,这样就不会引入任何同步并避免死锁。然后,您还可以任意更改发送和recv的发布顺序,例如,您可以对发送和recv进行配对,而不是在每个外部循环迭代时在一个大的for -循环中执行recv。
关于您关于内存消耗的第二个问题:可能相同:您在内部循环中发布的recv数量与进程数成线性增长,因此处理这些未完成的消息所需的内存量。
最后,我也同意前面的评论,即这看起来非常像一个集体MPI调用的情况,它完全取决于您在这里没有显示的应用程序代码,但是MPI_Alltoallv可能是一个很好的例子。
https://stackoverflow.com/questions/67722529
复制相似问题