MPI学习笔记(二):矩阵相乘的两种实现方法


mpi矩阵乘法(C=αAB+βC)

        最近领导让把之前安装的软件lapack、blas里的dgemm运算提取出来独立作为一套程序,然后把这段程序改为并行的,并测试一下进程规模扩展到128时的并行效率。
        我发现这个是dgemm.f文件,里面主要是对C=αAB+βC的实现,因此在此总结一下MPI的矩阵乘法使用。
        其主要思想:是把相乘的矩阵按行分解(任务分解),分别分给不同的进程,然后在汇总到一个进程上,在程序上实现则用到了主从模式,人为的把进程分为主进程和从进程,主进程负责对原始矩阵初始化赋值,并把数据均匀分发(为了负载均衡)到从进程上进行相乘运算,主要用到的知识是MPI点对点通信和组通信的机制。

一、使用简单的MPI_Send和MPI_Recv实现

#include 
#include "mpi.h"
#include 
#include "functions.h"

#define M 1000 // 矩阵维度
#define N 1100
#define K 900

int main(int argc, char **argv)
{
   int my_rank,comm_sz,line;
   double start, stop; //计时时间
   MPI_Status status;
   char Processorname[20];

   double *Matrix_A,*Matrix_B,*Matrix_C,*ans,*buffer_A,*buffer_C;
   double alpha=2,beta=2; // 系数C=aA*B+bC

   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
   MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);

   line=M/comm_sz; // 每个进程分多少行数据
   Matrix_A=(double*)malloc(M*N*sizeof(double));
   Matrix_B=(double*)malloc(N*K*sizeof(double));
   Matrix_C=(double*)malloc(M*K*sizeof(double));
   buffer_A=(double*)malloc(line*N*sizeof(double)); // A的均分行的数据
   buffer_C=(double*)malloc(line*K*sizeof(double)); // C的均分行的数据
   ans=(double*)malloc(line*K*sizeof(double)); // 临时保存部分数据计算结果

   // 给矩阵A B,C赋值
   if(my_rank==0){
      start=MPI_Wtime();
      for(int i=0;i

二、使用较高级的MPI_Scatter和MPI_Gather实现

#include 
#include "mpi.h"
#include 
#include "functions.h"

#define M 1200 // 矩阵维度
#define N 1000
#define K 1100

int main(int argc, char **argv)
{
   int my_rank,comm_sz,line;
   double start, stop; //计时时间
   MPI_Status status;

   double *Matrix_A,*Matrix_B,*Matrix_C,*ans,*buffer_A,*buffer_C,*result_Matrix;
   double alpha=2,beta=2; // 系数C=aA*B+bC

   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
   MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);

   line=M/comm_sz; // 每个进程分多少行数据
   Matrix_A=(double*)malloc(M*N*sizeof(double));
   Matrix_B=(double*)malloc(N*K*sizeof(double));
   Matrix_C=(double*)malloc(M*K*sizeof(double));
   buffer_A=(double*)malloc(line*N*sizeof(double)); // A的均分行的数据
   buffer_C=(double*)malloc(line*K*sizeof(double)); // C的均分行的数据
   ans=(double*)malloc(line*K*sizeof(double)); // 保存部分数据计算结果
   result_Matrix=(double*)malloc(M*K*sizeof(double)); // 保存数据计算结果

   // 给矩阵A B,C赋值
   if(my_rank==0){
      start=MPI_Wtime();
      for(int i=0;i   free(result_Marix);

   MPI_Finalize();
   return 0;
}  

三、结果分析

下图为上面两种方法的耗时:

1、 执行时间分析:
并行时,随着进程数目的增多,并行计算的时间越来越短;当达到一定的进程数时,执行时间小到最小值;然后再随着进程数的增多,执行时间反而越来越长。
2、加速比分析:
随着进程数的增大,加速比也是逐渐增大到最大值;再随着进程数的增大,加速比逐渐减小。
3、执行效率分析:
随着进程数的增大,程序执行效率不断降低

由于消息传递需要成本,而且不是每个进程都同时开始和结束,所以随着进程数的上升,平均每进程的效率下降

四、头文件functions.h内容

/********** 输出函数 **********/
void Matrix_print(double *A,int M,int N)
{
   for(int i=0;i

  

结束。

mpi