2014-07-25 44 views
2

我运行一个使用Boost MPI(1.55)在开放MPI(1.6.1)计算群集上项目。开放MPI和Boost MPI使用过多的文件句柄

我们的集群有一个有64个CPU的节点,我们产卵上的每个单一的MPI进程。我们大多数的沟通是在各个进程之间进行的,每个进程都打开一系列irecv()请求(针对不同的标记),并使用send()进行阻塞。

我们得到的问题是,处理(通常在10分钟)的短时间之后,我们得到这个错误,导致该程序结束:

[btl_tcp_component.c:1114:mca_btl_tcp_component_accept_handler] accept() failed: Too many open files in system (23). 

仔细调试表明,它是占用这些文件句柄的网络套接字,并且我们正在打开我们的操作系统限制的65536个文件句柄。其中大部分都处于“TIME_WAIT”状态,这显然是TCP在关闭套接字(通常是)后60秒(为了捕获任何延迟数据包)所做的工作。我的印象是Open MPI没有关闭套接字(http://www.open-mpi.org/faq/?category=tcp#tcp-socket-closing),只是保持打开N^2个套接字,以便所有进程都可以相互通信。很明显,65536远远超过64^2(涉及MPI的这个错误的最常见原因就是文件限制小于N^2),其中大多数是处于最近关闭状态的套接字。

我们的C++代码是太大,不适合这里,但我已经写了一些它的简化版本,以至少说明我们的实现,看看是否有与我们的技术的任何问题。我们在使用MPI时是否会导致OpenMPI关闭并重新打开太多套接字?

namespace mpi = boost::mpi; 
mpi::communicator world; 

bool poll(ourDataType data, mpi::request & dataReq, ourDataType2 work, mpi::request workReq) { 
    if(dataReq.test()) { 
    processData(data); // do a bunch of work 
    dataReq = world.irecv(mpi::any_source, DATATAG, data); 
    return true; 
    } 
    if(workReq.test()) { 
    int target = assess(work); 
    world.send(target, DATATAG, dowork); 
    world.irecv(mpi::any_source, WORKTAG, data); 
    return true; 
    } 
    return false; 
} 

bool receiveFinish(mpi::request finishReq) { 
    if (finishReq.test()) { 
    world.send(0, RESULTS, results); 
    resetSelf(); 
    finishReq = world.irecv(0, FINISH); 
    return true; 
    } 
    return false; 
} 

void run() { 
    ourDataType data; 
    mpi::request dataReq = world.irecv(mpi::any_source, DATATAG, data); 
    ourDataType2 work; 
    mpi::request workReq = world.irecv(mpi::any_source, WORKTAG, work); 
    mpi::request finishReq = world.irecv(0, FINISH); // the root process can call a halt 

    while(!receiveFinish(finishReq)) { 
    bool doWeContinue = poll(data, dataReq); 
    if(doWeContinue) { 
     continue; 
    } 
    // otherwise we do other work 
    results = otherwork(); 
    world.send(0, RESULTS, results); 
    } 
} 
+1

哦,亲爱的C++,所以请随身携带的巨大需要提醒的是,我不明白的语言下面......无论如何,我看不到任何MPI_WAIT或MPI_TEST - 只要你有一个无阻塞MPI宣传中应该相应的等待。我的怀疑是没有这些套接字没有被关闭,但我必须强调这是一个猜测,因为等待/测试可能在其他地方,或者C++可能比我目前认为的更加怪异。 –

+1

是的@IanBush,C++对我们不太友善。在Boost MPI层的顶部,像dataReq.test()这样的语句类似于特定irecv上的mpi_test。我不确定是否需要等待是否有定期轮询测试? – Marc

回答

1

这可能不是开放MPI开这么多插槽的真正原因,但你出现在poll()功能的以下部分是漏的请求:

if(workReq.test()) { 
    int target = assess(work); 
    world.send(target, DATATAG, dowork); 
    world.irecv(mpi::any_source, WORKTAG, data); // <------- 
    return true; 
} 

请求处理由返回的world.irecv()从不保存,因此丢失。如果在同一个workReq对象上周期性地调用,则此分支将在请求完成后的每个时间执行一次,因为测试已完成的请求始终返回true。因此,您将开始大量永不会等待或测试的非阻塞接收。更不用说发送的消息了。

receiveFinish中存在类似问题 - finishReq正在按值传递,并且分配不会影响run()中的值。

一个侧面说明:这是真的,你使用的代码?看起来您在run()中调用的poll()函数有两个参数,而这里的一个显示有四个参数,并且没有带默认值的参数。

+0

嗨Hristo,并感谢您的意见。这不是我们运行的代码,它基本上是它的解释版本,因为它非常庞大而且复杂。您指出的irecv行是一个错误,应该读取:'workReq = world.irecv(mpi :: any_source,WORKTAG,data);'然而,我看了一下我们的代码,并且确实通过了一些请求价值(而在其他地方参考)。这可能确实是问题的根源 – Marc

+0

它看起来像通过值而不是引用传递的请求是我的问题。感谢一群人发现它。 – Marc

+0

不客气。 –