来自MPI isend和irecv的意外结果

时间:2016-12-09 03:29:39

标签: asynchronous parallel-processing mpi nonblocking mpic++

我的目标是将流程0中的向量发送到流程1.然后,将流程从流程1发送回流程0.

我的实施中有两个问题,

1-为什么从进程1发送回进程0需要的时间比反之亦然? 第一个send-recv总共需要1e-4秒,第二个send-recv需要大约1秒。

2-当我增加向量的大小时,我得到以下错误。这个问题的原因是什么?

mpirun注意到节点server1上的PID 11248的进程等级0退出信号11(分段错误)。

我更新的C ++代码如下

#include <mpi.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <boost/timer/timer.hpp>
#include <math.h>
using namespace std;
int main(int argc, char** argv) {
    // Initialize the MPI environment
    MPI_Init(NULL, NULL);
    MPI_Request request, request2,request3,request4;

    MPI_Status status;

    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    srand( world_rank );

    int n = 1e3;


    double *myvector = new double[n];
    if (world_rank==0){
        myvector[n-1] = 1;
    }
    MPI_Barrier (MPI_COMM_WORLD);

    if (world_rank==0){

        boost::timer::cpu_timer timer;

        MPI_Isend(myvector, n, MPI_DOUBLE , 1, 0, MPI_COMM_WORLD, &request);

        boost::timer::cpu_times elapsedTime1 = timer.elapsed();
        cout << "  Wallclock time on Process 1:"
                << elapsedTime1.wall / 1e9 << " (sec)" << endl;

        MPI_Irecv(myvector, n, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &request4);
        MPI_Wait(&request4, &status);

        printf("Test if data is recieved from node 1: %1.0f\n",myvector[n-1]);

        boost::timer::cpu_times elapsedTime2 = timer.elapsed();
        cout <<"  Wallclock time on Process 1:"
                << elapsedTime2.wall / 1e9 << " (sec)" << endl;

    }else{
        boost::timer::cpu_timer timer;

        MPI_Irecv(myvector, n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request2);
        MPI_Wait(&request2, &status);

        boost::timer::cpu_times elapsedTime1 = timer.elapsed();
                cout << "  Wallclock time on Process 2:"
                        << elapsedTime1.wall / 1e9 << " (sec)" << endl;

        printf("Test if data is recieved from node 0: %1.0f\n",myvector[n-1]);
        myvector[n-1] = 2;
        MPI_Isend(myvector, n, MPI_DOUBLE , 0, 0, MPI_COMM_WORLD, &request3);
        boost::timer::cpu_times elapsedTime2 = timer.elapsed();
                cout<< "  Wallclock time on Process 2:"
                        << elapsedTime1.wall / 1e9 << " (sec)" << endl;

    }

    MPI_Finalize();

}

输出是:   过程1的挂钟时间:2.484e-05(秒)

进程2的挂钟时间:0.000125325(秒)

测试是否从节点0:1

收到数据

进程2的挂钟时间:0.000125325(秒)

测试是否从节点1:2

收到数据

进程1的挂钟时间:1.00133(秒)

1 个答案:

答案 0 :(得分:1)

时间差异

首先,您没有衡量发送邮件的时间。这就是为什么发布用于计时的实际代码是必不可少的。

您测量四次,对于两次发送,您只需拨打MPI_Isend的电话。这是API调用的立即版本。顾名思义,它立即完成。时间与发送消息的实际时间无关。

对于接收操作,您可以衡量MPI_Irecv和相应的MPI_Wait。这是启动接收和消息的本地可用性之间的时间。这又与邮件传输时间不同,因为它不考虑发布接收和相应发送之间的时间差。通常,您必须考虑延迟发件人延迟接收器案例。甚至对于阻止发送操作,本地完成并不意味着完成传输,远程完成甚至启动。

定时MPI转移很困难。

检查完成

还有一个问题是,为什么此代码中的任何内容可能需要一整秒。除非您的网络使用IPoAC,否则这当然不是一个明智的时间。可能的原因是您没有检查所有消息的完成情况。 MPI实现通常是单线程的,并且只能在相应的API调用期间在通信上取得进展。要使用即时消息,您必须定期致电MPI_Test*,直到请求完成或使用MPI_Wait*完成请求。

我不知道为什么你首先选择使用直接的MPI功能。如果您在开始MPI_Wait / MPI_Isend后立即致电MPI_Irecv,您也可以致电MPI_Send / MPI_Recv。您需要立即执行并发通信和计算的功能,以允许并发的不规则通信模式,并避免在某些情况下出现死锁。如果您不需要立即功能,请改用阻塞功能。

段错误

虽然我无法重现,但我怀疑这是由于两个同时运行的MPI操作使用相同的缓冲区(myvector)引起的。不要那样做。使用单独的缓冲区,或确保第一个操作完成。一般情况下 - 在您通过MPI_Isend / MPI_Irecv知道请求完成后,您无法以任何方式触摸缓冲区。MPI_Test*。

P.S。

如果您认为需要立即操作以避免在发送和接收时发生死锁,请考虑使用MPI_Wait*

相关问题