c - MPI_Allreduce 的高效使用

标签 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);

有人可以提示我该怎么做吗?

最佳答案

正如评论中已经暗示的那样,您在代码中遇到的错误是您没有传递包含发送和接收缓冲区的数组,而是传递了一些指向它们的指针。我想这个错误只是来自最初使用的单个元素(如 &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 缓冲区中,您无需显式复制。

关于c - MPI_Allreduce 的高效使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41741488/

相关文章:

c - memcpy 不是实际复制

c++ - OpenGL 截掉部分屏幕

c - 如何使用 MPI 或 OpenMP 并行化函数调用

c - PETSc - MatLUFactor - 不支持此对象类型的此操作

c++ - 编译的 C 可执行文件被 Windows Defender 检测为病毒

C 程序 : converting an if statement code to a code which does not use logical, 关系运算符或选择结构(允许 NO 开关)

c - 使用多线程 FFTW 时执行时间增加

c - 如何在发送端使用位移的 MPI_Gatherv?

c++ - ASCII 格式的 MPI 并行 IO(我该怎么做?)

c - C 中的循环语句