MPI_Barrier无法正常运行

MPI_Barrier doesn't function properly

本文关键字:正常运行 Barrier MPI      更新时间:2023-10-16

我写了下面的C应用程序来帮助我理解MPI,以及为什么MPI_Barrier()在我的大型c++应用程序中不起作用。但是,我能够在我的大型应用程序中用一个小得多的C应用程序再现我的问题。实际上,我在for循环中调用MPI_Barrier(),并且MPI_Barrier()对所有节点都是可见的,但是在循环的2次迭代之后,程序变成了死锁。任何想法吗?

#include <mpi.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
    MPI_Init(&argc, &argv);
    int i=0, numprocs, rank, namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Get_processor_name(processor_name, &namelen);
    printf("%s: Rank %d of %dn", processor_name, rank, numprocs);
    for(i=1; i <= 100; i++) {
            if (rank==0) printf("Before barrier (%d:%s)n",i,processor_name);
            MPI_Barrier(MPI_COMM_WORLD);
            if (rank==0) printf("After barrier (%d:%s)n",i,processor_name);
    }
    MPI_Finalize();
    return 0;
}
输出:

alienone: Rank 1 of 4
alienfive: Rank 3 of 4
alienfour: Rank 2 of 4
alientwo: Rank 0 of 4
Before barrier (1:alientwo)
After barrier (1:alientwo)
Before barrier (2:alientwo)
After barrier (2:alientwo)
Before barrier (3:alientwo)

我正在使用GCC 4.4,从Ubuntu 10.10存储库打开MPI 1.3。

另外,在我的c++应用程序中,MPI广播不起作用。只有一半的节点接收到广播,其他的都在等待。

提前感谢您的任何帮助或见解!

更新:升级到Open MPI 1.4.4,从源代码编译到/usr/local/

Update:将GDB附加到正在运行的进程中显示了一个有趣的结果。在我看来,MPI系统在屏障处死亡,但MPI仍然认为程序正在运行:

附加GDB产生一个有趣的结果。似乎所有节点都在MPI障碍处死亡,但MPI仍然认为它们正在运行:

0x00007fc235cbd1c8 in __poll (fds=0x15ee360, nfds=8, timeout=<value optimized out>) at   ../sysdeps/unix/sysv/linux/poll.c:83
83  ../sysdeps/unix/sysv/linux/poll.c: No such file or directory.
    in ../sysdeps/unix/sysv/linux/poll.c
(gdb) bt
#0  0x00007fc235cbd1c8 in __poll (fds=0x15ee360, nfds=8, timeout=<value optimized out>) at ../sysdeps/unix/sysv/linux/poll.c:83
#1  0x00007fc236a45141 in poll_dispatch () from /usr/local/lib/libopen-pal.so.0
#2  0x00007fc236a43f89 in opal_event_base_loop () from /usr/local/lib/libopen-pal.so.0
#3  0x00007fc236a38119 in opal_progress () from /usr/local/lib/libopen-pal.so.0
#4  0x00007fc236eff525 in ompi_request_default_wait_all () from /usr/local/lib/libmpi.so.0
#5  0x00007fc23141ad76 in ompi_coll_tuned_sendrecv_actual () from /usr/local/lib/openmpi/mca_coll_tuned.so
#6  0x00007fc2314247ce in ompi_coll_tuned_barrier_intra_recursivedoubling () from /usr/local/lib/openmpi/mca_coll_tuned.so
#7  0x00007fc236f15f12 in PMPI_Barrier () from /usr/local/lib/libmpi.so.0
#8  0x0000000000400b32 in main (argc=1, argv=0x7fff5883da58) at barrier_test.c:14
(gdb) 

:我也有这个代码:

#include <mpi.h>
#include <stdio.h>
#include <math.h>
int main( int argc, char *argv[] )  {
int n = 400, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
printf("MPI Rank %i of %i.n", myid, numprocs);
while (1) {
    h   = 1.0 / (double) n;
    sum = 0.0;
    for (i = myid + 1; i <= n; i += numprocs) {
        x = h * ((double)i - 0.5);
        sum += (4.0 / (1.0 + x*x));
    }
    mypi = h * sum;
    MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    if (myid == 0)
        printf("pi is approximately %.16f, Error is %.16fn",  pi, fabs(pi - PI25DT));
}
MPI_Finalize();
return 0;
}

尽管存在无限循环,但循环中的printf()只有一个输出:

mpirun -n 24 --machinefile /etc/machines a.out 
MPI Rank 0 of 24.
MPI Rank 3 of 24.
MPI Rank 1 of 24.
MPI Rank 4 of 24.
MPI Rank 17 of 24.
MPI Rank 15 of 24.
MPI Rank 5 of 24.
MPI Rank 7 of 24.
MPI Rank 16 of 24.
MPI Rank 2 of 24.
MPI Rank 11 of 24.
MPI Rank 9 of 24.
MPI Rank 8 of 24.
MPI Rank 20 of 24.
MPI Rank 23 of 24.
MPI Rank 19 of 24.
MPI Rank 12 of 24.
MPI Rank 13 of 24.
MPI Rank 21 of 24.
MPI Rank 6 of 24.
MPI Rank 10 of 24.
MPI Rank 18 of 24.
MPI Rank 22 of 24.
MPI Rank 14 of 24.
pi is approximately 3.1415931744231269, Error is 0.0000005208333338

任何想法吗?

OpenMPI中的MPI_Barrier()有时会在进程在最后一个屏障之后的不同时间遇到屏障时挂起,但是我可以看到这不是您的情况。无论如何,尝试使用MPI_Reduce()代替或在真正调用MPI_Barrier()之前。这并不直接等同于屏障,但任何几乎没有有效负载的同步调用都应该像屏障一样工作,其中涉及通信器中的所有进程。我还没有看到MPI_Barrier()在LAM/MPI或MPICH2甚至WMPI中的这种行为,但这是OpenMPI的一个真正的问题。

你有什么连接?它是像InfiniBand或Myrinet这样的专业网络,还是你只是在以太网上使用普通的TCP ?如果使用TCP传输运行,是否有多个已配置的网络接口?

此外,Open MPI是模块化的——有许多模块提供实现各种集合操作的算法。你可以尝试使用MCA参数来调整它们,例如,你可以通过传递mpirun类似--mca btl_base_verbose 30的东西来增加btl组件的冗长来开始调试应用程序的行为。查找类似于:

的内容
[node1:19454] btl: tcp: attempting to connect() to address 192.168.2.2 on port 260
[node2:29800] btl: tcp: attempting to connect() to address 192.168.2.1 on port 260
[node1:19454] btl: tcp: attempting to connect() to address 192.168.109.1 on port 260
[node1][[54886,1],0][btl_tcp_endpoint.c:638:mca_btl_tcp_endpoint_complete_connect] connect() to 192.168.109.1 failed: Connection timed out (110)

在这种情况下,一些(或所有)节点有多个已配置的网络接口,但不是所有节点都可以通过所有接口访问。这可能会发生,例如,如果节点运行最新的Linux发行版,默认启用了Xen支持(RHEL?),或者在它们上面安装了其他虚拟化软件,可以提供虚拟网络接口。

默认情况下,Open MPI是惰性的,即按需打开连接。如果选择了正确的接口,第一次发送/接收通信可能会成功,但后续操作可能会选择备选路径之一,以最大限度地提高带宽。如果另一个节点无法通过第二个接口到达,则可能发生超时,并且通信将失败,因为Open MPI将认为另一个节点关闭或有问题。

使用TCP btl模块的MCA参数隔离非连接网络或网络接口:

  • 强制打开MPI只使用特定的IP网络进行通信:--mca btl_tcp_if_include 192.168.2.0/24
  • 强制打开MPI只使用一些已知提供完整网络连接的网络接口:--mca btl_tcp_if_include eth0,eth1
  • 强制打开MPI 使用已知的私有/虚拟网络或属于其他不连接节点的网络接口(如果选择这样做,必须排除环回lo): --mca btl_tcp_if_exclude lo,virt0

有关详细信息,请参阅Open MPI运行时TCP调优FAQ。