?? cannon.c
字號:
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
/* 全局變量聲明 */
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<dg ; i++)
for(j=0; j<dg ; 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; 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<sp; l++)
{
/*矩陣塊相乘,c+=a*b */
for(i=0; i<dl; i++)
for(j=0; j<dl; j++)
for(k=0; k<dl; 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<dl;i++)
for(j=0;j<dl;j++)
C[i][j]=c[i*dl+j];
for (k=1;k<p;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<dg;i++)
{
for(j=0;j<dg;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<dl2 ; 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<dg; 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;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -