蝶形结构如下图所示
使用 蝶形结构 实现MPI_Allreduce
运行时,要求 线程的个数 必须是2n
#include <stdio.h>
#include <mpi.h>
const int MAX_SZ = 1024*1024/32;
int sum[MAX_SZ];
int temp[MAX_SZ];
void butterfly_sum(int my_rank, int size, int n){
int dst, step = 2;
//将
for(int i = 0; i < n; i++){
sum[i] = my_rank;
}
//蝶形求和
while(step <= size){
if(my_rank%step < step/2){
dst = my_rank + step/2;
}else{
dst = my_rank - step/2;
}
//蝶形分发
MPI_Sendrecv(sum, n, MPI_INT, dst, 0,
temp, n, MPI_INT, dst, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
for(int i = 0; i < n; i++)
sum[i] += temp[i];
step *= 2;
}
}
int main(){
int comm_sz, my_rank;
double start, end;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
for(int sz = 1; sz < MAX_SZ; sz+=1024){
MPI_Barrier(MPI_COMM_WORLD);
start = MPI_Wtime(); //开始时间
butterfly_sum(my_rank, comm_sz, sz);
end = MPI_Wtime(); //结束时间
printf("Rank : %d, result: %d\n", my_rank, sum[0]);
if(my_rank == 0){
printf("****************************************\n");
printf("* Size = %d, used time = %lf *\n", sz, (end-start));
printf("****************************************\n");
}
}
MPI_Finalize();
}
树形结构如下所示
广播的时候,把上面的树形结构倒过来看就可以了。
使用 树形结构 实现MPI_Allreduce
运行时,要求 线程的个数 必须是2n
#include <stdio.h>
#include <mpi.h>
const int MAX_SZ = 1024*1024/32;
int sum[MAX_SZ];
int temp[MAX_SZ];
void tree_sum(int my_rank, int size, int n){
int remain = size, half;
for(int i = 0; i < n; i++){
sum[i] = my_rank;
}
//求和
while(remain != 1){
half = remain /2;
if(my_rank < half){
MPI_Recv(&temp, n, MPI_INT, my_rank+half, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
for(int i = 0; i < n; i++)
sum[i] += temp[i];
}
else if(my_rank >= half){
MPI_Send(&sum, n, MPI_INT, my_rank - half, 0, MPI_COMM_WORLD);
remain = half;
break;
}
remain = half;
}
//将求和结果发送给所有进程
while(remain != size){
half = remain;
remain = remain * 2;
if(my_rank < half){
MPI_Send(&sum, n, MPI_INT, my_rank + half, 0, MPI_COMM_WORLD);
}else if(my_rank >= half && my_rank < remain){
MPI_Recv(&sum, n, MPI_INT, my_rank-half, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
}
}
int main(){
int comm_sz;
int my_rank;
double start, end;
MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
for(int sz = 1; sz < MAX_SZ; sz+=1024){
MPI_Barrier(MPI_COMM_WORLD);
start = MPI_Wtime(); //开始时间
tree_sum(my_rank, comm_sz, sz);
end = MPI_Wtime(); //结束时间
printf("Rank : %d, result: %d\n", my_rank, sum[0]);
if(my_rank == 0){
printf("****************************************\n");
printf("* Size = %d, used time = %lf *\n", sz, (end-start));
printf("****************************************\n");
}
}
MPI_Finalize();
}
使用MPI_Allreduce
#include <stdio.h>
#include <mpi.h>
const int MAX_SZ = 1024*1024/32;
int sum[MAX_SZ];
int temp[MAX_SZ];
int main(){
int comm_sz, my_rank;
double start, end;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
for(int sz = 1; sz < MAX_SZ; sz+=1024){
MPI_Barrier(MPI_COMM_WORLD);
start = MPI_Wtime(); //开始时间
for(int i = 0; i < sz; i++)
sum[i] = my_rank;
MPI_Allreduce(sum, temp, sz, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
end = MPI_Wtime(); //结束时间
printf("Rank : %d, result: %d\n", my_rank, temp[0]);
if(my_rank == 0){
printf("****************************************\n");
printf("* Size = %d, used time = %lf *\n", sz, (end-start));
printf("****************************************\n");
}
}
MPI_Finalize();
}