cannon.c
上传用户:hhyinxing
上传日期:2013-09-10
资源大小:833k
文件大小:7k
源码类别:

并行计算

开发平台:

Unix_Linux

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <mpi.h>
  4. #include <time.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. /* 全局变量声明 */
  8. float **A, **B, **C;              /* 总矩阵,C = A * B */
  9. float *a, *b, *c, *tmp_a, *tmp_b; /* a、b、c表分块,tmp_a、tmp_b表缓冲区 */
  10. int dg, dl, dl2,p, sp;            /* dg:总矩阵维数;dl:矩阵块维数;dl2=dl*dl;p:处理器个数;sp=sqrt(p) */
  11. int my_rank, my_row, my_col;      /* my_rank:处理器ID;(my_row,my_col):处理器逻辑阵列坐标 */
  12. MPI_Status status;
  13. /*
  14.  *函数名: get_index
  15.  *功能:处理器逻辑阵列坐标至rank号的转换
  16.  *输入:坐标、逻辑阵列维数
  17.  *输出:rank号
  18.  */
  19. int get_index(int row, int col, int sp)
  20. {
  21.    return ((row+sp)%sp)*sp + (col+sp)%sp;
  22. }
  23. /*
  24.  *函数名:random_A_B
  25.  *功能:随机生成矩阵A和B
  26.  */
  27. void random_A_B()
  28. {
  29.    int i,j;
  30.     srand((unsigned int)time(NULL));     /*设随机数种子*/
  31. /*随机生成A,B,并初始化C*/
  32.     for(i=0; i<dg ; i++)
  33.       for(j=0; j<dg ; j++)
  34.   {
  35.     A[i][j] = rand();
  36.         B[i][j] = rand();
  37.         C[i][j] = 0.0;
  38.   }
  39. }
  40. /* 函数名:scatter_A_B
  41.  * 功能:rank为0的处理器向其他处理器发送A、B矩阵的相关块
  42.  */
  43. void scatter_A_B()
  44. {
  45.    int i,j,k,l;
  46.    int p_imin,p_imax,p_jmin,p_jmax;
  47.    for(k=0; k<p; k++)
  48.    {
  49.   /*计算相应处理器所分得的矩阵块在总矩阵中的坐标范围*/
  50.   p_jmin = (k % sp    ) * dl;
  51.      p_jmax = (k % sp + 1) * dl-1;
  52.   p_imin = (k - (k % sp))/sp * dl;
  53.   p_imax = ((k - (k % sp))/sp +1) *dl -1;
  54.       l = 0;
  55.       /*rank=0的处理器将A,B中的相应块拷至tmp_a,tmp_b,准备向其他处理器发送*/
  56.       for(i=p_imin; i<=p_imax; i++)
  57.       {
  58.          for(j=p_jmin; j<=p_jmax; j++)
  59.          {
  60.               tmp_a[l] = A[i][j];
  61.       tmp_b[l] = B[i][j];
  62.       l++;
  63.           }
  64.       }
  65.       /*rank=0的处理器直接将自己对应的矩阵块从tmp_a,tmp_b拷至a,b*/
  66.       if(k==0)
  67.       {
  68.          memcpy(a, tmp_a, dl2 * sizeof(float));
  69.  memcpy(b, tmp_b, dl2 * sizeof(float));
  70.       } else   /*rank=0的处理器向其他处理器发送tmp_a,tmp_b中相关的矩阵块*/
  71.       {
  72.           MPI_Send(tmp_a, dl2, MPI_FLOAT, k, 1, MPI_COMM_WORLD);
  73.   MPI_Send(tmp_b, dl2, MPI_FLOAT, k, 2, MPI_COMM_WORLD);
  74.       }
  75.    }
  76. }
  77. /*
  78.  *函数名:init_alignment
  79.  *功能:矩阵A和B初始对准
  80.  */
  81. void init_alignment()
  82. {
  83.    /*将A中坐标为(i,j)的分块A(i,j)向左循环移动i步*/
  84.    MPI_Sendrecv(a, dl2, MPI_FLOAT, get_index(my_row,my_col-my_row,sp), 1,
  85.             tmp_a, dl2, MPI_FLOAT, get_index(my_row,my_col+my_row,sp), 1, MPI_COMM_WORLD, &status);
  86.    memcpy(a, tmp_a, dl2 * sizeof(float) );
  87.    /*将B中坐标为(i,j)的分块B(i,j)向上循环移动j步*/
  88.    MPI_Sendrecv(b, dl2, MPI_FLOAT, get_index(my_row-my_col,my_col,sp), 1,
  89.             tmp_b, dl2, MPI_FLOAT, get_index(my_row+my_col,my_col,sp), 1, MPI_COMM_WORLD, &status);
  90.    memcpy(b, tmp_b, dl2 * sizeof(float) );
  91. }
  92. /*
  93.  *函数名:main_shift
  94.  *功能:分块矩阵左移和上移,并计算分块c
  95.  */
  96. void main_shift()
  97. {
  98.    int i,j,k,l;
  99.    for(l=0; l<sp; l++)
  100.    {
  101.      /*矩阵块相乘,c+=a*b */
  102.      for(i=0; i<dl; i++)
  103.        for(j=0; j<dl; j++)
  104.          for(k=0; k<dl; k++)
  105.            c[i*dl+j] += a[i*dl+k]*b[k*dl+j];
  106.       /* 将分块a左移1位 */
  107.       MPI_Send(a , dl2, MPI_FLOAT, get_index(my_row, my_col-1, sp), 1, MPI_COMM_WORLD);
  108.       MPI_Recv(a , dl2, MPI_FLOAT, get_index(my_row, my_col+1, sp), 1, MPI_COMM_WORLD, &status);
  109.       /* 将分块b上移1位 */
  110.       MPI_Send(b , dl2, MPI_FLOAT, get_index(my_row-1, my_col, sp), 1, MPI_COMM_WORLD);
  111.       MPI_Recv(b , dl2, MPI_FLOAT, get_index(my_row+1, my_col, sp), 1, MPI_COMM_WORLD, &status);
  112.    }
  113. }
  114. /*
  115.  *函数名:collect_c
  116.  *功能:rank为0的处理器从其余处理器收集分块矩阵c
  117.  */
  118. void collect_C()
  119. {
  120.    int i,j,i2,j2,k;
  121.    int p_imin,p_imax,p_jmin,p_jmax; /* 分块矩阵在总矩阵中顶点边界值 */
  122.    /* 将rank为0的处理器中分块矩阵c结果赋给总矩阵C对应位置 */
  123.    for (i=0;i<dl;i++)
  124.  for(j=0;j<dl;j++)
  125.    C[i][j]=c[i*dl+j];
  126.    for (k=1;k<p;k++)
  127.    {
  128.        /*将rank为0的处理器从其他处理器接收相应的分块c*/
  129.        MPI_Recv(c, dl2, MPI_FLOAT, k, 1, MPI_COMM_WORLD, &status);
  130.        p_jmin = (k % sp    ) *dl;
  131.        p_jmax = (k % sp + 1) *dl-1;
  132.        p_imin =  (k - (k % sp))/sp     *dl;
  133.        p_imax = ((k - (k % sp))/sp +1) *dl -1;
  134.        i2=0;
  135.        /*将接收到的c拷至C中的相应位置,从而构造出C*/
  136.        for(i=p_imin; i<=p_imax; i++)
  137.        {
  138.            j2=0;
  139.            for(j=p_jmin; j<=p_jmax; j++)
  140.            {
  141.                C[i][j]=c[i2*dl+j2];
  142.                j2++;
  143.            }
  144.            i2++;
  145.        }
  146.    }
  147. }
  148. /*函数名:print
  149.  *功能:打印矩阵
  150.  *输入:指向矩阵指针的指针,字符串
  151.  */
  152. void print(float **m,char *str)
  153. {
  154.    int i,j;
  155.    printf("%s",str);
  156.    /*打印矩阵m*/
  157.    for(i=0;i<dg;i++)
  158.    {
  159.        for(j=0;j<dg;j++)
  160.            printf("%15.0f    ",m[i][j]);
  161.        printf("n");
  162.    }
  163.    printf("n");
  164. }
  165. /*
  166.  *函数名:main
  167.  *功能:主过程,Cannon算法,矩阵相乘
  168.  *输入:argc为命令行参数个数,argv为每个命令行参数组成的字符串数组
  169.  */
  170. int main(int argc, char *argv[])
  171. {
  172.    int i;
  173.    MPI_Init(&argc, &argv);                  /* 启动MPI计算 */
  174.    MPI_Comm_size(MPI_COMM_WORLD, &p);       /* 确定处理器个数 */
  175.    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /* 确定各自的处理器标识符 */
  176.    sp = sqrt(p);
  177.    /* 确保处理器个数是完全平方数,否则打印错误信息,程序退出 */
  178.    if (sp*sp != p)
  179.    {
  180.       if (my_rank == 0)
  181.   printf("Number of processors is not a quadratic number!n");
  182.       MPI_Finalize();
  183.       exit(1);
  184.    }
  185.    if (argc != 2)
  186.    {
  187.       if (my_rank == 0)
  188.           printf("usage: mpirun -np ProcNum cannon MatrixDimensionn");
  189.       MPI_Finalize();
  190.       exit(1);
  191.    }
  192.    dg  = atoi(argv[1]);    /* 总矩阵维数 */
  193.    dl  = dg / sp;          /* 计算分块矩阵维数 */
  194.    dl2 = dl * dl;
  195.    /* 计算处理器在逻辑阵列中的坐标 */
  196.    my_col =  my_rank % sp ;
  197.    my_row = (my_rank-my_col) / sp ;
  198.    /* 为a、b、c分配空间 */
  199.    a = (float *)malloc( dl2 * sizeof(float) );
  200.    b = (float *)malloc( dl2 * sizeof(float) );
  201.    c = (float *)malloc( dl2 * sizeof(float) );
  202.    /* 初始化c */
  203.    for(i=0; i<dl2 ; i++)
  204.      c[i] = 0.0;
  205.    /* 为tmp_a、tmp_b分配空间 */
  206.    tmp_a = (float *)malloc( dl2 * sizeof(float) );
  207.    tmp_b = (float *)malloc( dl2 * sizeof(float) );
  208.    if (my_rank == 0)
  209.    {
  210.       /* rank为0的处理器为A、B、C分配空间 */
  211.       A = (float **)malloc( dg * sizeof(float*) );
  212.       B = (float **)malloc( dg * sizeof(float*) );
  213.       C = (float **)malloc( dg * sizeof(float*) );
  214.       for(i=0; i<dg; i++)
  215.       {
  216.          A[i] = (float *)malloc( dg * sizeof(float) );
  217.          B[i] = (float *)malloc( dg * sizeof(float) );
  218.          C[i] = (float *)malloc( dg * sizeof(float) );
  219.       }
  220.       random_A_B();     /* rank为0的处理器随机化生成A、B矩阵 */
  221.       scatter_A_B();    /* rank为0的处理器向其他处理器发送A、B矩阵的相关块 */
  222.    } else               /* rank不为0的处理器接收来自rank为0的处理器的相应矩阵分块 */
  223.    {
  224.        MPI_Recv(a, dl2, MPI_FLOAT, 0 , 1, MPI_COMM_WORLD, &status);
  225.        MPI_Recv(b, dl2, MPI_FLOAT, 0 , 2, MPI_COMM_WORLD, &status);
  226.    }
  227.    init_alignment();    /* A、B矩阵的初始对准 */
  228.    main_shift();        /* 分块矩阵左移、上移, cannon算法的主过程 */
  229.    if(my_rank == 0)
  230.    {
  231.      collect_C();       /* rank为0的处理器从其余处理器收集分块矩阵c */
  232.      print(A,"random matrix A : n");  /* 打印矩阵A */
  233.  print(B,"random matrix B : n");  /* 打印矩阵B */
  234.  print(C,"Matrix C = A * B : n");     /* 打印矩阵C */
  235.    } else
  236.    {
  237.       MPI_Send(c,dl2,MPI_FLOAT,0,1,MPI_COMM_WORLD); /* rank不为0的处理器向rank为0的处理器发送矩阵块c */
  238.    }
  239.    MPI_Barrier(MPI_COMM_WORLD);        /* 同步所有处理器 */
  240.    MPI_Finalize();                     /* 结束MPI计算 */
  241.    return 0;
  242. }