cannon算法的mpi_Cannon算法的MPI程序

这个博客详细介绍了如何使用MPI并行计算库实现Cannon算法,用于矩阵乘法。通过随机生成矩阵A和B,然后将矩阵分散到多个处理器上,进行矩阵的初始化对准、主过程的矩阵左移和上移操作,最后收集并组合各处理器的结果得到最终的矩阵C。
摘要由CSDN通过智能技术生成

#include 

#include 

#include 

#include 

#include 

#include 

/* 全局变量声明 */

float **A, **B, **C;              /* 总矩阵,C = A * B */

float *a, *b, *c, *tmp_a, *tmp_b; /* a、b、c表分块,tmp_a、tmp_b表缓冲区 */

int dg, dl, dl2,p, sp;            /* dg:总矩阵维数;dl:矩阵块维数;dl2=dl*dl;p:处理器个数;sp=sqrt(p) */

int my_rank, my_row, my_col;      /* my_rank:处理器ID;(my_row,my_col):处理器逻辑阵列坐标 */

MPI_Status status;

/*

*函数名: get_index

*功能:处理器逻辑阵列坐标至rank号的转换

*输入:坐标、逻辑阵列维数

*输出:rank号

*/

int get_index(int row, int col, int sp)

{

return ((row+sp)%sp)*sp + (col+sp)%sp;

}

/*

*函数名:random_A_B

*功能:随机生成矩阵A和B

*/

void random_A_B()

{

int i,j;

srand((unsigned int)time(NULL));     /*设随机数种子*/

/*随机生成A,B,并初始化C*/

for(i=0; i

for(j=0; j

{

A[i][j] = rand();

B[i][j] = rand();

C[i][j] = 0.0;

}

}

/* 函数名:scatter_A_B

* 功能:rank为0的处理器向其他处理器发送A、B矩阵的相关块

*/

void scatter_A_B()

{

int i,j,k,l;

int p_imin,p_imax,p_jmin,p_jmax;

for(k=0; k

{

/*计算相应处理器所分得的矩阵块在总矩阵中的坐标范围*/

p_jmin = (k % sp    ) * dl;

p_jmax = (k % sp + 1) * dl-1;

p_imin = (k - (k % sp))/sp * dl;

p_imax = ((k - (k % sp))/sp +1) *dl -1;

l = 0;

/*rank=0的处理器将A,B中的相应块拷至tmp_a,tmp_b,准备向其他处理器发送*/

for(i=p_imin; i<=p_imax; i++)

{

for(j=p_jmin; j<=p_jmax; j++)

{

tmp_a[l] = A[i][j];

tmp_b[l] = B[i][j];

l++;

}

}

/*rank=0的处理器直接将自己对应的矩阵块从tmp_a,tmp_b拷至a,b*/

if(k==0)

{

memcpy(a, tmp_a, dl2 * sizeof(float));

memcpy(b, tmp_b, dl2 * sizeof(float));

} else   /*rank=0的处理器向其他处理器发送tmp_a,tmp_b中相关的矩阵块*/

{

MPI_Send(tmp_a, dl2, MPI_FLOAT, k, 1, MPI_COMM_WORLD);

MPI_Send(tmp_b, dl2, MPI_FLOAT, k, 2, MPI_COMM_WORLD);

}

}

}

/*

*函数名:init_alignment

*功能:矩阵A和B初始对准

*/

void init_alignment()

{

/*将A中坐标为(i,j)的分块A(i,j)向左循环移动i步*/

MPI_Sendrecv(a, dl2, MPI_FLOAT, get_index(my_row,my_col-my_row,sp), 1,

tmp_a, dl2, MPI_FLOAT, get_index(my_row,my_col+my_row,sp), 1, MPI_COMM_WORLD, &status);

memcpy(a, tmp_a, dl2 * sizeof(float) );

/*将B中坐标为(i,j)的分块B(i,j)向上循环移动j步*/

MPI_Sendrecv(b, dl2, MPI_FLOAT, get_index(my_row-my_col,my_col,sp), 1,

tmp_b, dl2, MPI_FLOAT, get_index(my_row+my_col,my_col,sp), 1, MPI_COMM_WORLD, &status);

memcpy(b, tmp_b, dl2 * sizeof(float) );

}

/*

*函数名:main_shift

*功能:分块矩阵左移和上移,并计算分块c

*/

void main_shift()

{

int i,j,k,l;

for(l=0; l

{

/*矩阵块相乘,c+=a*b */

for(i=0; i

for(j=0; j

for(k=0; k

c[i*dl+j] += a[i*dl+k]*b[k*dl+j];

/* 将分块a左移1位 */

MPI_Send(a , dl2, MPI_FLOAT, get_index(my_row, my_col-1, sp), 1, MPI_COMM_WORLD);

MPI_Recv(a , dl2, MPI_FLOAT, get_index(my_row, my_col+1, sp), 1, MPI_COMM_WORLD, &status);

/* 将分块b上移1位 */

MPI_Send(b , dl2, MPI_FLOAT, get_index(my_row-1, my_col, sp), 1, MPI_COMM_WORLD);

MPI_Recv(b , dl2, MPI_FLOAT, get_index(my_row+1, my_col, sp), 1, MPI_COMM_WORLD, &status);

}

}

/*

*函数名:collect_c

*功能:rank为0的处理器从其余处理器收集分块矩阵c

*/

void collect_C()

{

int i,j,i2,j2,k;

int p_imin,p_imax,p_jmin,p_jmax; /* 分块矩阵在总矩阵中顶点边界值 */

/* 将rank为0的处理器中分块矩阵c结果赋给总矩阵C对应位置 */

for (i=0;i

for(j=0;j

C[i][j]=c[i*dl+j];

for (k=1;k

{

/*将rank为0的处理器从其他处理器接收相应的分块c*/

MPI_Recv(c, dl2, MPI_FLOAT, k, 1, MPI_COMM_WORLD, &status);

p_jmin = (k % sp    ) *dl;

p_jmax = (k % sp + 1) *dl-1;

p_imin =  (k - (k % sp))/sp     *dl;

p_imax = ((k - (k % sp))/sp +1) *dl -1;

i2=0;

/*将接收到的c拷至C中的相应位置,从而构造出C*/

for(i=p_imin; i<=p_imax; i++)

{

j2=0;

for(j=p_jmin; j<=p_jmax; j++)

{

C[i][j]=c[i2*dl+j2];

j2++;

}

i2++;

}

}

}

/*函数名:print

*功能:打印矩阵

*输入:指向矩阵指针的指针,字符串

*/

void print(float **m,char *str)

{

int i,j;

printf("%s",str);

/*打印矩阵m*/

for(i=0;i

{

for(j=0;j

printf("%15.0f    ",m[i][j]);

printf("\n");

}

printf("\n");

}

/*

*函数名:main

*功能:主过程,Cannon算法,矩阵相乘

*输入:argc为命令行参数个数,argv为每个命令行参数组成的字符串数组

*/

int main(int argc, char *argv[])

{

int i;

MPI_Init(&argc, &argv);                  /* 启动MPI计算 */

MPI_Comm_size(MPI_COMM_WORLD, &p);       /* 确定处理器个数 */

MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /* 确定各自的处理器标识符 */

sp = sqrt(p);

/* 确保处理器个数是完全平方数,否则打印错误信息,程序退出 */

if (sp*sp != p)

{

if (my_rank == 0)

printf("Number of processors is not a quadratic number!\n");

MPI_Finalize();

exit(1);

}

if (argc != 2)

{

if (my_rank == 0)

printf("usage: mpirun -np ProcNum cannon MatrixDimension\n");

MPI_Finalize();

exit(1);

}

dg  = atoi(argv[1]);    /* 总矩阵维数 */

dl  = dg / sp;          /* 计算分块矩阵维数 */

dl2 = dl * dl;

/* 计算处理器在逻辑阵列中的坐标 */

my_col =  my_rank % sp ;

my_row = (my_rank-my_col) / sp ;

/* 为a、b、c分配空间 */

a = (float *)malloc( dl2 * sizeof(float) );

b = (float *)malloc( dl2 * sizeof(float) );

c = (float *)malloc( dl2 * sizeof(float) );

/* 初始化c */

for(i=0; i

c[i] = 0.0;

/* 为tmp_a、tmp_b分配空间 */

tmp_a = (float *)malloc( dl2 * sizeof(float) );

tmp_b = (float *)malloc( dl2 * sizeof(float) );

if (my_rank == 0)

{

/* rank为0的处理器为A、B、C分配空间 */

A = (float **)malloc( dg * sizeof(float*) );

B = (float **)malloc( dg * sizeof(float*) );

C = (float **)malloc( dg * sizeof(float*) );

for(i=0; i

{

A[i] = (float *)malloc( dg * sizeof(float) );

B[i] = (float *)malloc( dg * sizeof(float) );

C[i] = (float *)malloc( dg * sizeof(float) );

}

random_A_B();     /* rank为0的处理器随机化生成A、B矩阵 */

scatter_A_B();    /* rank为0的处理器向其他处理器发送A、B矩阵的相关块 */

} else               /* rank不为0的处理器接收来自rank为0的处理器的相应矩阵分块 */

{

MPI_Recv(a, dl2, MPI_FLOAT, 0 , 1, MPI_COMM_WORLD, &status);

MPI_Recv(b, dl2, MPI_FLOAT, 0 , 2, MPI_COMM_WORLD, &status);

}

init_alignment();    /* A、B矩阵的初始对准 */

main_shift();        /* 分块矩阵左移、上移, cannon算法的主过程 */

if(my_rank == 0)

{

collect_C();       /* rank为0的处理器从其余处理器收集分块矩阵c */

print(A,"random matrix A : \n");  /* 打印矩阵A */

print(B,"random matrix B : \n");  /* 打印矩阵B */

print(C,"Matrix C = A * B : \n");     /* 打印矩阵C */

} else

{

MPI_Send(c,dl2,MPI_FLOAT,0,1,MPI_COMM_WORLD); /* rank不为0的处理器向rank为0的处理器发送矩阵块c */

}

MPI_Barrier(MPI_COMM_WORLD);        /* 同步所有处理器 */

MPI_Finalize();                     /* 结束MPI计算 */

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值