我在每个处理器上都有一个带有数字的列表range
。我想确定这些列表range
的每一行的最大数量。
每个处理器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);
有人可以给我一个提示,我该怎么做?
答案 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
缓冲区中,从而使您无需显式执行复制。