【问题标题】:Memory-efficient MPI parallel implementation of element-wise sum of multiple arrays多个数组的元素总和的内存高效 MPI 并行实现
【发布时间】:2019-12-02 16:46:18
【问题描述】:

我对 MPI 很陌生,我想计算两个(或更多)大型数组的元素总和。 这个任务的幼稚实现是这样的(对于这个伪代码的任何错误,我深表歉意。如果标准实现有很大不同,请告诉我):

#include<stdio.h>
#include<stdlib.h>
#include<mpi.h>
#define NELEMS 10
#define NP 2
#define TAG 15

int setElements(int,int);

int postProcess(int *);

int main(int argc,char **argv){
    int nprocs,myrank,*myarray,*result,i,initflag=0;
    MPI_Status status;
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
    myarray=malloc(sizeof(int)*NELEMS);
    if(myrank==0){
        result=malloc(sizeof(int)*NELEMS);
        if(myrank==0){
            result[i]=0;
        }
        initflag=1;
        for(i=1;i<NP;i++){
            MPI_Send(&initflag,1,MPI_INT,i,TAG,MPI_COMM_WORLD);
        }
    }
    for(i=0;i<NELEMS;i++){
        myarray[i]=setElements(myrank,i);
    }
    if(myrank!=0){
        MPI_Recv(&initflag,1,MPI_INT,0,TAG,MPI_COMM_WORLD,&status);
    }
    MPI_Reduce(myarray,result,NELEMS,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);
    MPI_Finalize();
    free(myarray);
    /*At this point the element-wise sum should be stored on myrank==0*/
    if(myrank==0){
        postProcess(result);
    }
    free(result);
    return 0;
}

我担心的是,这个实现需要myrank==0 分配两个大小为NELEMS 的数组(而一个用于myrank!=0),这对于大的NELEMS 可能有问题。一种简单的解决方法(如果可用)是多使用一个处理器并使myrank==0 空闲,直到在其他进程中完成setElements 循环,但这似乎不是非常有效地使用处理器,尤其是在评估@987654329 时@ 计算量很大。

所以我的问题是:有没有更聪明的方法来使用 MPI 计算大型数组的元素总和?还是我应该考虑一个完全不同的策略?

【问题讨论】:

  • OT:在MPI_Isend 中,您缺少最后一个参数,即指向MPI_Request 的指针。为什么是MPI_Isend 而不仅仅是MPI_Send?另请注意,free(result) 不适用于未初始化 result 的从站。将其初始化为nullptr,或free,仅用于master。
  • @DanielsaysreinstateMonica 哎呀。我最初使用MPI_Send 发布了我的问题,但后来我注意到如果setElements 计算量很大,这是低效的。所以我改为MPI_Isend,但我不应该这样做:可能更好的方法是简单地将MPI_Recv 块移动到setElements 循环上方。
  • 据我所见,您确实编写了 C 代码。因此,我删除了标签c++。社区对标签垃圾邮件有点敏感......
  • @Scheff 我真诚地道歉:该标签是系统建议的。在实际插入之前我应该​​三思而后行。感谢您的删除。
  • 标签是系统提示的哦。我不知道有这样的自动化。这就解释了为什么它会定期出现在问题中。

标签: c mpi


【解决方案1】:

您可以在根进程上就地执行缩减。引用文档:

当通信器是内部通信器时,您可以就地执行reduce操作(输出缓冲区用作输入缓冲区)。使用变量MPI_IN_PLACE 作为根进程sendbuf 的值。在这种情况下,输入数据从接收缓冲区的根处获取,在那里它将被输出数据替换。

在您的情况下,修改 MPI_Reduce 调用来自:

MPI_Reduce(myarray,result,NELEMS,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);

到:

if (my_rank == 0)
  MPI_Reduce(MPI_IN_PLACE,myarray,NELEMS,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);
else
  MPI_Reduce(myarray,nullptr,NELEMS,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);

使用这种方法,您根本不需要第二个数组 (result)。

【讨论】:

  • 哦,我不知道MPI_IN_PLACE。在检查这是否对我有用(现在+1)后,我很乐意接受您的回答。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2014-09-27
  • 2011-06-24
  • 2019-05-12
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多