boost::mpi在具有相同标记的多个isend/irecv传输上抛出mpi_ERR_TRUNCATE

boost::mpi throws MPI_ERR_TRUNCATE on multiple isend/irecv transfers with same tag

本文关键字:mpi 传输 irecv TRUNCATE ERR isend boost      更新时间:2023-10-16

当使用序列化数据对同一标记执行多个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 tagsn";
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 tagsn";
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_empl>的未捕获异常: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中是否存在缺陷?

在当前版本的boost 1.55中,boost::mpi不保证不超过消息。这与底层的MPI API形成了鲜明对比,后者确实做到了:

订单消息不可超越:如果发件人在连续到相同目的地并且两者都匹配相同的接收,如果第一条消息是,则此操作无法接收第二条消息仍处于挂起状态。如果接收方连续发布两个接收方,并且两者都匹配相同的消息,则第二个接收操作无法如果第一条消息仍处于挂起状态,请对此消息感到满意。这该要求有助于匹配发送和接收。它保证如果进程单线程且通配符MPI_ANY_SOURCE未在中使用接收。

boost::mpi不能保证不超越的原因是,序列化的数据类型在两个MPI消息中传输,一个用于大小,一个用作有效载荷,而第二个消息的irecv在检查第一个消息之前无法发布。

正在考虑一项保证boost::mpi不超车的建议。从这里开始,可以在boost::mpi邮件列表中找到进一步的讨论。

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

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

解决方案是预先发布接收缓冲区。在您的情况下,您可以将所有isendirecv调用推送到同一个向量中,并让MPI处理所有内容。这将允许MPI访问所有的接收缓冲区,这样您的消息就有了用武之地。