MPI在消息大小为2 ^ 16时仅接收零

时间:2014-05-21 22:35:06

标签: c++ boost mpi

对于我正在处理的物理代码,我们最近遇到了一个问题,当我们增加问题大小以使某些mpi消息高于2 ^ 16(包括sizeof())时,这些消息只被接收为0。对于该大小之前的消息,通信正确进行。

谷歌解决这个问题让我相信这个问题可能是由于'急切限制'造成的:见thisthis

我们目前的沟通模式是我们发布isend的模式,然后继续我们的执行。在接收端,我们在执行完成后执行iprobes,循环遍历所有活动的iprobes并在消息存在时重新进行。

到目前为止,我尝试最小化这个问题的尝试还没有成功:

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>
#include <vector>

int main(int argc, char* argv[]){
    boost::mpi::environment env;
    boost::mpi::communicator world;
    int length = 16384;

    std::vector<double> send(length, 5.0);
    std::vector<double> noise(length, 10.0);
    std::vector<double> receive(length);

    std::cout<<"Sent: "<<std::endl<<std::endl;
    for( std::vector<double>::const_iterator i = send.begin(); i != send.end(); ++i)
        std::cout<<*i<<" ";
    std::cout<<std::endl<<std::endl;
    std::cout<<send.size()*sizeof(int)<<std::endl;
    boost::mpi::request req = world.isend(0, 1, &send[0], send.size());

    boost::optional<boost::mpi::status> msg = world.iprobe();
    while(!msg){
        msg = world.iprobe();
    }
    boost::mpi::request noisereq = world.isend(0,1, &noise[0], noise.size());
    world.recv(0, 1, &receive[0], length);
    std::cout<<"Received: "<<std::endl<<std::endl;
    for( std::vector<double>::const_iterator i = receive.begin(); i != receive.end(); ++i)
        std::cout<<*i<<" ";
    std::cout<<std::endl;
    req.wait();

    return 0;
}

不幸的是,对于我来说,编译和运行时没有(在这种情况下)只接收0的所需效果。发布实际代码不是一种选择。我将继续尝试编辑上面的代码,尝试通过使代码更接近我们正在做的事情来观察失败,但基本思想已经如上所述。

我们认为将第一个iprobe更改为irecv,然后将循环更改为状态对象的测试可能有助于解决问题,但我们不明白问题是什么足以确定。

为什么通过急切限制导致我们收到0? 为什么它在此之前没有失败? 如果我们做错了什么,它为什么会收到0而不是崩溃? 我们如何让我们的代码工作?

问题最初是在Open MPI上观察到的,它也发生在MPICH和MVAPICH2上。


由于我无法回答这个问题,但我确实找到了答案:

这项练习使上述内容更接近我们在代码中所做的工作,这非常有用,并且发现了错误以及为什么急切的限制很重要。此代码现在的行为与我们的代码非常相似:

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

template<typename numeric>
void cout_vector(std::vector<numeric> & v)
{
    for( typename std::vector<numeric>::const_iterator i = v.begin(); i != v.end(); i++)
        std::cout<<*i<<" ";
    std::cout<<std::endl;
}

template<typename T>
boost::mpi::request Send( const int destID, const int tag, const std::vector<T>& send, boost::mpi::communicator& world)
{
    std::vector<T> buffer(send);
    boost::mpi::request req = world.isend(destID, tag, &buffer[0], buffer.size() );
    return req;
}

template<typename T>
void Receive(const int srcID, const int tag, T& recieve, boost::mpi::communicator& world)
{
    world.recv(srcID, tag, &recieve[0], recieve.size());
} 

int main(int argc, char* argv[]){
    boost::mpi::environment env;
    boost::mpi::communicator world;
    int length = 16384;

    std::vector<double> send(length, 5.0);
    std::vector<double> noise(length, 0.0);
    std::vector<double> receive(length);

    std::cout<<"Sent: "<<std::endl<<std::endl;
    cout_vector(send);
    std::cout<<std::endl;
    std::cout<<send.size()*sizeof(int)<<std::endl;

    boost::mpi::request req = Send(0, 1, send, world);

    boost::optional<boost::mpi::status> msg = world.iprobe();
    while(!msg){
        msg = world.iprobe();
    }

    boost::mpi::request noisereq = Send(0,2, noise, world);
    Receive(0, 1, receive, world);
    std::cout<<"Received: "<<std::endl<<std::endl;
    cout_vector(receive);
    req.wait();

    return 0;
}

原因是发送缓冲区不够持久:低于预期限制,自动发送放在该缓冲区中的所有内容,并且缓冲区的非持久性无关紧要,超出缓冲区损坏的预期限制(在接收发生之前被破坏或重用,因为发送不会发生。

更改为irecv并首先发布,摆脱iprobe而不是测试irecv的状态确实解决了问题。一旦发布了isend,就会发生通信。

确保缓冲区的持久性也可以解决问题。

0 个答案:

没有答案