⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cannon.c

📁 并行算法的cannon算法实现。在smp环境下用c编写。
💻 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 + -