MPI_Barrier无法正常运行

时间:2011-11-22 16:20:31

标签: c++ c mpi openmpi

我在下面写了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 %d\n", 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 Broadcasts不起作用。只有一半的节点接收广播,其他节点则等待它。

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

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

更新:将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 %.16f\n",  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

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

你有什么互联?它是一个像InfiniBand或Myrinet这样的专家吗?或者你只是使用普通的TCP over Ethernet?如果使用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是懒惰的,即connectinos是按需打开的。如果拾取了正确的接口,则第一发送/接收通信可能成功,但是后续操作可能拾取备用路径之一以便最大化带宽。如果通过第二个接口无法访问另一个节点,则可能会发生超时,并且通信将失败,因为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 run-time TCP tuning FAQ