【问题标题】:MPI_send MPI_recv failed while increase the arry sizeMPI_send MPI_recv 在增加数组大小时失败
【发布时间】:2015-01-26 05:33:10
【问题描述】:

我正在尝试使用 OpenMPI 1.6.4 版编写一个 3D 并行计算泊松求解器。

以下部分是我使用阻塞发送接收进行并行计算的代码。

以下变量在另一个文件中声明。

int px = lx*meshx; //which is meshing point in x axis.
int py = ly*meshy;
int pz = lz*meshz;
int L = px * py * pz

以下代码运行良好,而

lx=ly=lz=10;

meshx=meshy=2, meshz=any int number.

meshx 和 meshy 大于 4 时发送 recv 部分失败。

挂在那里等待发送或接收数据的程序。

但如果我只将数据从一个处理器发送到另一个处理器,而不是交换数据,它就可以工作。 (即:从等级 0 发送到 1,但不要从 1 发送到 0)

当 meshx 和 meshy 很小但网格数 x y 很大时,我无法理解这段代码是如何工作的。

阻塞发送接收进程是否会自行中断,或者我在代码中混淆了处理器?这与我的数组大小有关系吗?

#include "MPI-practice.h"

# include <iostream>
# include <math.h>
# include <string.h>
# include <time.h>
# include <sstream>
# include <string>

# include "mpi.h"


using namespace std;


extern int px,py,pz;
extern int L;
extern double simTOL_phi;
extern vector<double> phi;

int main(int argc, char *argv[]){

    int   numtasks, taskid, offset_A, offset_B, DD_loop,s,e;
    double errPhi(0),errPhi_sum(0);

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
    MPI_Status status;

    if((pz-1)%numtasks!=0){
        //cerr << "can not properly divide meshing points."<<endl;
        exit(0);
    }

    offset_A=(pz-1)/numtasks*px*py;
    offset_B=((pz-1)/numtasks+1)*px*py;

    s=offset_A*taskid;
    e=offset_A*taskid+offset_B;


    int pz_offset_A=(pz-1)/numtasks;
    int pz_offset_B=(pz-1)/numtasks+1;

    stringstream name1;
    string name2;

    Setup_structure();
    Initialize();
    Build_structure();

    if (taskid==0){
        //master processor

        ofstream  output;
        output.open("time", fstream::out | fstream::app);
        output.precision(6);

        clock_t start,end;

        start=clock();

        do{
            errPhi_sum=0;

            errPhi=Poisson_inner(taskid,numtasks,pz_offset_A,pz_offset_B);
            //Right exchange

            MPI_Send(&phi[e-px*py], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD);
            MPI_Recv(&phi[e], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD, &status);

            MPI_Allreduce ( &errPhi, &errPhi_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );

        }while(errPhi_sum>simTOL_phi);

        end=clock();
        output << "task "<< 0 <<" = "<< (end-start)/CLOCKS_PER_SEC <<endl<<endl;

        Print_to_file("0.txt");

        //recv from slave
        for (int i=1;i<numtasks;i++){
            MPI_Recv(&phi[offset_A*i], offset_B, MPI_DOUBLE, i, 1, MPI_COMM_WORLD, &status);
        }

        Print_to_file("sum.txt");

    }
    else{
        //slave processor

        do{

            errPhi=Poisson_inner(taskid,numtasks,pz_offset_A,pz_offset_B);

            //Left exchange
            MPI_Send(&phi[s+px*py], px*py, MPI_DOUBLE, taskid-1, 1, MPI_COMM_WORLD);
            MPI_Recv(&phi[s], px*py, MPI_DOUBLE, taskid-1, 1, MPI_COMM_WORLD, &status);



            //Right exchange
            if(taskid!=numtasks-1){
                MPI_Send(&phi[e-px*py], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD);
                MPI_Recv(&phi[e], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD, &status);
            }

            MPI_Allreduce ( &errPhi, &errPhi_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );

        }while(errPhi_sum>simTOL_phi);

        //send back master
        MPI_Send(&phi[s], offset_B, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);

        name1<<taskid<<".txt";
        name2=name1.str();
        Print_to_file(name2.c_str());


    }

    MPI_Finalize();
}

【问题讨论】:

    标签: c++ parallel-processing mpi simulator


    【解决方案1】:

    将所有耦合的MPI_Send/MPI_Recv 调用替换为对MPI_Sendrecv 的调用。比如这个

    MPI_Send(&phi[e-px*py], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD);
    MPI_Recv(&phi[e], px*py, MPI_DOUBLE, taskid+1, 1, MPI_COMM_WORLD, &status);
    

    变成

    MPI_Sendrecv(&phi[e-px*py], px*py, MPI_DOUBLE, taskid+1, 1,
                 &phi[e], px*px, MPI_DOUBLE, taskid+1, 1,
                 MPI_COMM_WORLD, &status);
    

    MPI_Sendrecv 在内部使用非阻塞操作,因此即使两个队列同时相互发送,它也不会死锁。唯一的要求(和往常一样)是每次发送都与接收匹配。

    【讨论】:

      【解决方案2】:

      问题出在你最内层的循环中。两个任务同时进行阻塞发送,然后挂起。它不会因较小的数据集而挂起,因为 MPI 库有足够大的缓冲区来保存数据。但是,一旦您将其增加到缓冲区大小之外,发送会阻塞两个进程。由于两个进程都没有尝试接收,因此两个缓冲区都不能清空,程序就会死锁。

      要解决这个问题,让从机先从主机接收,然后再发回数据。如果您的发送/接收不冲突,您可以切换功能的顺序。否则你需要创建一个临时缓冲区来保存它。

      【讨论】:

      • 谢谢!正如你所说,我只是通过使用额外的缓冲区来修复它。
      猜你喜欢
      • 1970-01-01
      • 2013-04-12
      • 2011-11-11
      • 2016-04-22
      • 2014-04-17
      • 2011-01-24
      • 1970-01-01
      • 2016-09-09
      • 2017-10-25
      相关资源
      最近更新 更多