1. 程式人生 > >智障大學一附院精神科主任醫師胡老師

智障大學一附院精神科主任醫師胡老師

學習筆記-矩陣乘的MPI實現

目前還是萌新,看了兩天書,自己硬著頭皮寫出來了。主要思想是書中介紹的,主程序將矩陣A的各行依此傳送給從程序,從程序計算該行與矩陣B的相乘結果,並向主程序傳送這一結果。

#include<stdio.h>
#include"mpi.h"

#define A_ROW 500
#define A_CLO_B_ROW 600
#define B_CLO 700
#define SHUT_DOWN_TAG -1

int main(void)
{
  //初始化
  int mat1[A_ROW][A_CLO_B_ROW];
  int mat2[A_CLO_B_ROW][B_CLO];
  for(int i=0;i<A_CLO_B_ROW;i++)
  {
    for(int j=0;j<A_ROW;j++){
      //mat1[j][i]=j*10+i;
      mat1[j][i]=1;
    }
    for(int k=0;k<B_CLO;k++){
      //mat2[i][k]=i*10+k;
      mat2[i][k]=1;
    }
  }
  //result
  int res[A_ROW][B_CLO];
  //記時
  double start_time,end_time;
  double m_time;
  //並行
  int l,m,n,send_row;
  int task_num;
  int rank,size;
  MPI_Status status;
  int vec1[B_CLO];
  int vec2[A_CLO_B_ROW];
  MPI_Init(NULL,NULL);
  start_time=MPI_Wtime();
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  MPI_Comm_size(MPI_COMM_WORLD,&size);
  task_num=(A_ROW+size-2)/(size-1);//向上取整
  for(l=0;l<task_num;l++)//傳送接收task_num輪
  {
    if(rank==0)//主程序
    {
      for(m=0;m<size-1;m++)//傳送給剩下size-1個程序
      {
        send_row=m+l*(size-1);//計算髮送矩陣1的行號(0~A_ROW-1)
        if(send_row<A_ROW)//行號小於矩陣1的行數
        {
          for(int o=0;o<A_CLO_B_ROW;o++){
            vec2[o]=mat1[send_row][o];//該行資料放入緩衝區vect中
          }
          MPI_Send(vec2,A_CLO_B_ROW,MPI_INT,m+1,send_row,MPI_COMM_WORLD);//傳送給對應的程序
          //printf("master has send %d row to process %d \n",send_row,m+1);
        }//本輪發送結束
      }
      //開始本輪接收
      for(int rec=0;rec<size-1;rec++){
        MPI_Recv(vec1,B_CLO,MPI_INT,MPI_ANY_SOURCE,rec+l*(size-1),MPI_COMM_WORLD,&status);//接收對應行號的結果
        //printf("master has receive res %d row from %d process\n",rec+l*(size-1),status.MPI_SOURCE);
		      for(int s=0;s<B_CLO;s++)//存放到結果矩陣中
          {
        		res[status.MPI_TAG][s]=vec1[s];
		      }
        if(status.MPI_TAG==A_ROW-1){//結束
          end_time=MPI_Wtime();
          m_time=end_time-start_time;
          printf("%d !\n",res[0][0]);
          printf("time:%f s \n",m_time);
          printf("speed_up= %f for %d process!\n",c_time/m_time,size);
          MPI_Abort(MPI_COMM_WORLD,99);
        }
      }
    }
  else//其餘程序
  {
      MPI_Recv(vec2,A_CLO_B_ROW,MPI_INT,0,MPI_ANY_TAG,MPI_COMM_WORLD,&status);//接收自己的資料
      if(status.MPI_TAG==SHUT_DOWN_TAG){
        MPI_Barrier(MPI_COMM_WORLD);
        printf("process exit!",rank);
      }
      else{
      //printf("process %d has recieve %d row!\n",rank,status.MPI_TAG);
      for(int p=0;p<B_CLO;p++){
        int elem=0;
        for(int r=0;r<A_CLO_B_ROW;r++){
          elem+=vec2[r]*mat2[r][p];
        }
        vec1[p]=elem;
      }//橫向量寫入到vec
      MPI_Send(vec1,B_CLO,MPI_INT,0,rank+l*(size-1)-1,MPI_COMM_WORLD);//傳送
      //printf("process has send %d\n",rank+l*(size-1)-1);
  }
}
}
  MPI_Finalize();
}