【问题标题】:Why wont MPI finalize gracefully?为什么 MPI 不能优雅地完成?
【发布时间】:2012-01-15 03:57:39
【问题描述】:

每当我尝试完成我的 mpi 程序时,都会收到类似于以下内容的错误。

[mpiexec] HYDT_dmxu_poll_wait_for_event (./tools/demux/demux_poll.c:70): assert (!(pollfds[i].revents & ~POLLIN & ~POLLOUT & ~POLLHUP)) failed
[mpiexec] main (./pm/pmiserv/pmip.c:221): demux engine error waiting for event
[mpiexec] HYDT_bscu_wait_for_completion (./tools/bootstrap/utils/bscu_wait.c:99): one of the processes terminated badly; aborting
[mpiexec] HYDT_bsci_wait_for_completion (./tools/bootstrap/src/bsci_wait.c:18): bootstrap device returned error waiting for completion
[mpiexec] HYD_pmci_wait_for_completion (./pm/pmiserv/pmiserv_pmci.c:352): bootstrap server returned error waiting for completion
[mpiexec] main (./ui/mpich/mpiexec.c:294): process manager error waiting for completion

有时,它会得到 glibc “双重释放或损坏”错误。每个进程都是单线程的,并且每个进程肯定会调用 MPI_Finalize()。知道这里可能出了什么问题吗?

【问题讨论】:

  • 您确定每个进程都在调用 MPI_Finalize 吗?你能转储 MPI_Finalize 函数的返回码吗?就像 int ret_code = MPI_Finalize(); if(0 == my_rank) fprintf(stderr, "Process, return_code"); fprintf(stderr, "%i, %i", my_rank, ) 然后 1) 计算行数——应该等于 MPI 进程数,否则有些进程实际上并没有调用 MPI_Finalize; 2) 检查所有错误代码是否相似。
  • 是的,我确定。问题是最后一个进程何时调用它。我转储错误代码并打印它们。所有进程都返回 0,除了等级为 0 的进程不返回任何内容。它只是在 finalize 时崩溃并显示此错误消息。我什至可以让第 0 个进程休眠 5 秒,然后看到其他进程也保持在 finalize 状态,但是一旦进程 0 调用 finalize,就会崩溃。
  • 现在,我不确定发生了什么,因为当我试图找出错误(主要是通过在 finalize 周围添加一堆打印语句)时,它停止了它。现在我不能再复制错误了。

标签: linux mpi


【解决方案1】:

我编写了一个小测试程序,它应该可以退出而不会出现任何错误。请尝试运行它。如果它正常退出,那么问题出在您的代码上。

#include <mpi.h>
#include <cstdio>

int main(int argc, char *argv[])
{
    MPI_Init(&argc, &argv);
    int my_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    int finalize_retcode = MPI_Finalize();
    if(0 == my_rank) fprintf(stderr, "Process, return_code\n");
    fprintf(stderr, "%i, %i\n", my_rank, finalize_retcode);
    return 0;
}

【讨论】:

  • 它确实可以运行,我确信问题出在我的代码上。我只是不确定从哪里开始寻找。我想我的问题是,假设我正确调用了 MPI_Init(正如你所做的那样),并且为每个进程调用 MPI_Finalize(),那么两者之间的哪种代码可能导致这次崩溃?
  • 我不知道什么样的代码会导致这样的问题......如果我是你我会做一个错误的二进制搜索:删除程序的一半,然后如果错误仍然存​​在,删除另一个等。我还尝试将我的代码简化为类似于上面程序的代码,从而仔细检查它是否有效,即基本的东西确实有效。检查您是否使用相同的 MPI 通信器,当您调用 MPI_Finalize 时,可能您的进程 #0 已更改它。检查您是否没有两次调用某些 MPI 设置例程 - 也许这很重要,尽管我不确定。
  • 堆损坏错误通常直到您的程序后期才会出现,根据我的经验,MPI_Finalize() 将发现您可能因注销数组末尾而导致的任何内存错误,使用 new /free() 或 malloc()/delete(在 C++ 中)等...很多工具可以帮助您发现这类错误(例如 valgrind、valgrind.org/docs/manual/mc-manual.html#mc-manual.mpiwrap),我认为您的直觉是正确的 - 这不是 MPI 问题。最有可能的是,在您最后一次 free() 或删除内存与您调用 MPI_Finalize() 之间的某个地方发生了错误。
【解决方案2】:

我刚刚遇到了类似的问题。

    MPI_Request* req = (MPI_Request*) malloc(sizeof(MPI_Request)*2*numThings*numItems);
    int count;
    for( item in items ) {
       count = 0;
       for( thing in things ) {
          MPI_Irecv(<sendBufF>, 1, MPI_INT, <src>, <tag>, MPI_COMM_WORLD, &req[count++]);
          MPI_Isend(<recvBufF>, 1, MPI_INT, <dest>, <tag>, MPI_COMM_WORLD, &req[count++]);
       }
    } 

    MPI_Status* stat = (MPI_Status*) malloc(sizeof(MPI_Status)*2*numThings*numItems);
    MPI_Waitall(count, req, stat);

MPI_Waitall(...) 的调用使用count 的值进行,该值小于Isend 和recv 执行的次数;这会导致收不到消息。将 count=0 移到 for 循环之外解决了 MPI_Finalize(...) 错误。

【讨论】:

  • 谢谢!我有一个测试用例在 MPI_Finalize 上随机崩溃,这就是确切的问题。我在 MPI_Waital 的消息参数 # 中有错字。
猜你喜欢
  • 2015-12-15
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 2015-08-21
  • 1970-01-01
相关资源
最近更新 更多