【问题标题】:boost::mpi throws MPI_ERR_TRUNCATE on multiple isend/irecv transfers with same tagboost::mpi 在具有相同标签的多个 isend/irecv 传输上抛出 MPI_ERR_TRUNCATE
【发布时间】:2014-03-20 07:28:00
【问题描述】:

在使用序列化数据执行具有相同标签的多个 isend/irecv 传输时,我看到 boost::mpi 出现 MPI_ERR_TRUNCATE 错误。这些是并发传输,即不涉及线程。同一时间只有不止一项转让未完成。这是一个显示失败的简短测试程序:

#include <iostream>
#include <string>
#include <vector>
#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>

static const size_t N = 2;

int main() {
   boost::mpi::environment env;
   boost::mpi::communicator world;

#if 1
   // Serialized types fail.
   typedef std::string DataType;
#define SEND_VALUE "how now brown cow"
#else
   // Native MPI types succeed.
   typedef int DataType;
#define SEND_VALUE 42
#endif

   DataType out(SEND_VALUE);
   std::vector<DataType> in(N);
   std::vector<boost::mpi::request> sends;
   std::vector<boost::mpi::request> recvs;
   sends.reserve(N);
   recvs.reserve(N);

   std::cout << "Multiple transfers with different tags\n";
   sends.clear();
   recvs.clear();
   for (size_t i = 0; i < N; ++i) {
      sends.push_back(world.isend(0, i, out));
      recvs.push_back(world.irecv(0, i, in[i]));
   }
   boost::mpi::wait_all(sends.begin(), sends.end());
   boost::mpi::wait_all(recvs.begin(), recvs.end());

   std::cout << "Multiple transfers with same tags\n";
   sends.clear();
   recvs.clear();
   for (size_t i = 0; i < N; ++i) {
      sends.push_back(world.isend(0, 0, out));
      recvs.push_back(world.irecv(0, 0, in[i]));
   }
   boost::mpi::wait_all(sends.begin(), sends.end());
   boost::mpi::wait_all(recvs.begin(), recvs.end());

   return 0;
}

在这个程序中,我首先在不同的标签上进行 2 次传输,效果很好。然后我尝试在同一个标​​签上进行 2 次传输,但失败:

libc++abi.dylib: 以 boost::exception_detail::clone_impl 类型的未捕获异常终止 >: MPI_Unpack: MPI_ERR_TRUNCATE: 消息被截断

如果我使用本机 MPI 数据类型以便不调用序列化,那么一切似乎都有效。我在使用 OpenMPI 1.7.3 的 MacPorts boost 1.55 和使用 OpenMPI 1.4.5 的 Debian boost 1.49 上遇到了同样的错误。我尝试了直接使用 API C 接口使用相同标签进行多次传输,并且似乎可以正常工作,当然我只能传输本机 MPI 数据类型。

我的问题是,在同一个标​​签上有多个未完成的传输是否是对boost::mpi 的有效操作,如果是这样,我的程序中是否存在错误或boost::mpi 中的错误?

【问题讨论】:

    标签: c++ boost mpi boost-mpl


    【解决方案1】:

    在当前版本的 boost, 1.55, boost::mpi 不保证不超车消息。这与底层的MPI API which does 形成对比:

    Order Messages are non-overtaking:如果发件人在 连续到同一个目的地,并且都匹配同一个接收, 如果第一个消息,则此操作无法接收第二个消息 依然悬而未决。如果接收者连续发布两个接收,并且 都匹配相同的消息,则第二个接收操作不能 如果第一个消息仍在等待中,请对此消息感到满意。这 要求有助于匹配发送到接收。它保证 消息传递代码是确定性的,如果进程是 单线程和通配符 MPI_ANY_SOURCE 不用于 收到。

    boost::mpi 不保证不超车的原因是序列化数据类型在两条 MPI 消息中传输,一个用于大小,一个用于负载,而 irecv 用于第二条消息,直到第一条消息被发送检查。

    正在考虑一项保证boost::mpi 不超车的提案。可以在boost::mpi 邮件列表中找到更多讨论,以here 开头。

    【讨论】:

      【解决方案2】:

      问题可能是您正在等待所有发送完成,然后等待所有接收。 MPI 期望您的发送和接收在时间和数量上匹配。我所说的意思是,如果没有接听电话,您就无法完成所有的发送电话。

      MPI 通常处理发送消息的方式是,当您调用 send 时,只要库处理完消息,它就会从调用中返回。这可能是消息已被复制到内部缓冲区,或者消息实际上已传输到远程进程并已被接收。无论哪种方式,消息都必须到达某个地方。如果您没有等待的接收缓冲区,则必须在内部缓冲消息。最终,实现将耗尽这些缓冲区并开始做坏事(例如向用户返回错误),您可能会在此处看到。

      解决方案是预先发布您的接收缓冲区。在您的情况下,您可以将所有 isendirecv 调用推送到同一个向量中,让 MPI 处理所有事情。这将使 MPI 可以访问所有接收缓冲区,因此您的消息可以有去处。

      【讨论】:

      • 感谢您的回复,但事实并非如此。 send 和 recv 的发布顺序不会改变测试的行为。如果我只等待接收而不等待发送,行为也是一样的。至于缓冲,请注意我正在调用 isend()irecv(),它们不使用 MPI 缓冲(任何缓冲都在 boost::mpi 中完成)。
      • 它没有显式使用缓冲,但是 MPI 的实现确实使用了缓冲。您是否尝试将发送和接收放在同一个向量中?
      • 单次发送和接收即可工作。我的目的不是避免测试程序中的错误;就是判断行为是否正确。另请注意,直接调用 MPI C API 时,多个isend/irecv 传输有效,即绕过boost::mpi
      • 我并不是说将它们组合成一个调用。我的意思是让它们在同一个向量中排队,以便 MPI 可以同时在发送和接收方面取得进展。
      • 您的意思是将isendirecv 请求放入同一个容器中,所以我只调用wait_all 一次而不是两次?如果是这样,那将无济于事(我刚刚验证了它)。您无需等待我知道的任何 MPI 实现的异步请求,即可在主流操作系统的幕后取得进展——这是提供 isendirecv 调用的主要原因之一。我认为这可能仅适用于非常原始的操作系统的实现。
      猜你喜欢
      • 2017-07-14
      • 2012-03-31
      • 1970-01-01
      • 2017-04-24
      • 2012-11-05
      • 1970-01-01
      • 2013-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多