有效使用MPI_Allreduce

时间:2017-01-19 12:10:39

标签: c mpi

我在每个处理器上都有一个带有数字的列表range。我想确定这些列表range的每一行的最大数量。

enter image description here

每个处理器P0-P3的前四个列表range。红色列表包含MPI_Allreduce之后每个处理器获得的每一行的最大值。

以下是我的代码的工作版本:

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <mpi.h>

//#define KEY_MAX 100

typedef struct{
    int myrank;
    int numprocs;
    int *range;
} SubDomainKeyTree;

void compRange(SubDomainKeyTree *s, int myrank, int numprocs){
    s->myrank = myrank;
    s->numprocs = numprocs;

    // Allocate memory for (numprocs+1) ranges
    s->range = malloc((numprocs+1) * sizeof(int));
    // Compute range values
    for(int p=0; p<=numprocs; p++){
        s->range[p] = rand()%100;
    }

    for(int p=0; p<s->numprocs; p++){
        if(s->myrank == p){
        for(int k=0; k<=s->numprocs; k++){
            printf("Processor %d: %d random number is %d\n", p, k, s->range[k]);
        }
        printf("\n");
        }
    }
    }

    void compDynRange(SubD *s){

        int rangeForAll[s->numprocs+1];
        //////////////////////////////////
        // This is not really efficient //
        //////////////////////////////////
        for(int r=0; r<=s->numprocs; r++){
            MPI_Allreduce(&s->range[r], &rangeForAll[r], 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
        }

    for(int p=0; p<s->numprocs; p++){
        if(s->myrank == p){
            for(int k=0; k<=s->numprocs; k++){
                s->range[k] = rangeForAll[k];
                printf("Processor %d: %d random number after MPI_Allreduce is %d\n", p, k, s->range[k]);
            }
            printf("\n");
        }
    }
}

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

    int nameLen;
    char processorName[MPI_MAX_PROCESSOR_NAME];

    int myrank;           // Rank of processor
    int numprocs;         // Number of processes
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Get_processor_name(processorName,&nameLen);
    MPI_Status status;

    time_t t;
    srand((unsigned)time(NULL)+myrank*numprocs+nameLen);

    SubD s;
    compRange(&s, myrank, numprocs);

    compDynRange(&s);
    MPI_Finalize();
    return 0;
}

我使用for循环对我来说效率非常低。在这里,我一个接一个地计算所有列表的每一行的最大值。

但是,如果没有for循环,我可以使用MPI_Allreduce吗?

我已经尝试过了,而不是没有用的for循环。

MPI_Allreduce(&s->range, &rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);

有人可以给我一个提示,我该怎么做?

1 个答案:

答案 0 :(得分:1)

正如已经在评论中暗示的那样,您在代码中遇到的错误是,不是传递包含发送和接收缓冲区的数组,而是传递了一些指针。我想这个错误只是简单地从最初使用的单个元素(如&s->range[r])变为完全正确,只需删除索引访问(即&s->range)错。

正如所解释的那样,使用:

MPI_Allreduce(s->range, rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD)

就是诀窍。但是,由于您希望将结果导入s->range数组而不是临时rangeFarAll数组,因此最好根本不定义后者,并使用MPI_IN_PLACE关键字作为发送参数,s->range作为接收参数。电话会变成:

MPI_Allreduce(MPI_IN_PLACE, s->range, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD)

s->range同时充当发送和接收缓冲区。因此,最终结果将在调用后全部位于s->range缓冲区中,从而使您无需显式执行复制。