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

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

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

#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
#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<M;i++){
for(int j=0;j<N;j++)
Matrix_A[i*N+j]=i+1;
}
for(int i=0;i<N;i++){
for(int j=0;j<K;j++)
Matrix_B[i*K+j]=j+1;
}
for(int i=0;i<M;i++){
for(int j=0;j<K;j++)
Matrix_C[i*K+j]=1;
} // 输出A,B,C
/*Matrix_print(Matrix_A,M,N);
Matrix_print(Matrix_B,N,K);
Matrix_print(Matrix_C,M,K);
*/
/*将矩阵广播出去*/
for(int i=1;i<comm_sz;i++){
MPI_Send(Matrix_A+(i-1)*line*N,line*N,MPI_DOUBLE,i,66,MPI_COMM_WORLD);
MPI_Send(Matrix_C+(i-1)*line*K,line*K,MPI_DOUBLE,i,99,MPI_COMM_WORLD);
}
MPI_Bcast(Matrix_B,N*K,MPI_DOUBLE,0,MPI_COMM_WORLD); // 接收从进程的计算结果
for(int p=1;p<comm_sz;p++){
MPI_Recv(ans,line*K,MPI_DOUBLE,p,33,MPI_COMM_WORLD,&status);
for(int i=0;i<line;i+=comm_sz)
for(int j=0;j<K;j++)
Matrix_C[((p-1)*line+i)*K+j]=ans[i*K+j];
} // 计算A剩下的行数据
for(int i=(comm_sz-1)*line;i<M;i++){
for(int j=0;j<K;j++){
double temp=0;
for(int p=0;p<N;p++)
temp+=Matrix_A[i*N+p]*Matrix_B[p*K+j];
Matrix_C[i*K+j]=alpha*temp+beta*Matrix_C[i*K+j];
}
} //Matrix_print(Matrix_C,M,K);
stop=MPI_Wtime(); printf("rank:%d time:%lfs\n",my_rank,stop-start); free(Matrix_A);
free(Matrix_B);
free(Matrix_C);
free(buffer_A);
free(buffer_C);
free(ans);
}
else{
//接收广播的数据
MPI_Recv(buffer_A,line*N,MPI_DOUBLE,0,66,MPI_COMM_WORLD,&status);
MPI_Recv(buffer_C,line*K,MPI_DOUBLE,0,99,MPI_COMM_WORLD,&status);
MPI_Bcast(Matrix_B,N*K,MPI_DOUBLE,0,MPI_COMM_WORLD); //计算乘积结果,并将结果发送给主进程
for(int i=0;i<line;i++){
for(int j=0;j<K;j++){
double temp=0;
for(int p=0;p<N;p++){
temp+=buffer_A[i*N+p]*Matrix_B[p*K+j];
}
ans[i*line+j]=alpha*temp+beta*buffer_C[i*K+j];
}
}
MPI_Send(ans,line*K,MPI_DOUBLE,0,33,MPI_COMM_WORLD);
} MPI_Finalize();
return 0;
}

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

#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
#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<M;i++){
for(int j=0;j<N;j++)
Matrix_A[i*N+j]=i+1;
for(int p=0;p<K;p++)
Matrix_C[i*K+p]=1;
}
for(int i=0;i<N;i++){
for(int j=0;j<K;j++)
Matrix_B[i*K+j]=j+1;
} // 输出A,B,C
//Matrix_print(Matrix_A,M,N);
//Matrix_print(Matrix_B,N,K);
//Matrix_print(Matrix_C,M,K);
} // 数据分发
MPI_Scatter(Matrix_A,line*N,MPI_DOUBLE,buffer_A,line*N,MPI_DOUBLE,0,MPI_COMM_WORLD);
MPI_Scatter(Matrix_C,line*K,MPI_DOUBLE,buffer_C,line*K,MPI_DOUBLE,0,MPI_COMM_WORLD);
// 数据广播
MPI_Bcast(Matrix_B,N*K,MPI_DOUBLE,0,MPI_COMM_WORLD); // 计算 结果
for(int i=0;i<line;i++){
for(int j=0;j<K;j++){
double temp=0;
for(int p=0;p<N;p++)
temp+=buffer_A[i*N+p]*Matrix_B[p*K+j];
ans[i*K+j]=alpha*temp+beta*buffer_C[i*K+j];
}
}
// 结果聚集
MPI_Gather(ans,line*K,MPI_DOUBLE,result_Matrix,line*K,MPI_DOUBLE,0,MPI_COMM_WORLD); // 计算A剩下的行数据
if(my_rank==0){
int rest=M%comm_sz;
if(rest!=0){
for(int i=M-rest-1;i<M;i++)
for(int j=0;j<K;j++){
double temp=0;
for(int p=0;p<N;p++)
temp+=Matrix_A[i*N+p]*Matrix_B[p*K+j];
result_Matrix[i*K+j]=alpha*temp+beta*Matrix_C[i*K+j];
}
} //Matrix_print(result_Matrix,M,K);
stop=MPI_Wtime(); printf("rank:%d time:%lfs\n",my_rank,stop-start);
} free(Matrix_A);
free(Matrix_B);
free(Matrix_C);
free(ans);
free(buffer_A);
free(buffer_C);
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<M;i++){
for(int j=0;j<N;j++)
printf("%.1f ",A[i*N+j]);
printf("\n");
}
printf("\n");
}

  

结束。

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

  1. javaweb学习总结(二十一)——JavaWeb的两种开发模式

    SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...

  2. Linux学习笔记21——线程同步的两种方式

    一  用信号量同步 1 信号量函数的名字都以sem_开头,线程中使用的基本信号量函数有4个 2 创建信号量 #include<semaphore.h> int sem_init(sem_t ...

  3. python学习笔记30(全局变量的两种解决办法)

    先看程序: >>> count = 0 >>> def fuc(count): print count count +=1 >>> for i i ...

  4. LINUX编程学习笔记(十三) 遍历目录的两种方法

    1 默认情况下  实际用户和有效用户是一样的 实际用户:执行用户   有效用户:权限用户 getuid()  实际用户 geteuid() 有效用户 chmod u+s 之后 ,其他人执行文件时,实际 ...

  5. TensorFlow+实战Google深度学习框架学习笔记(10)-----神经网络几种优化方法

    神经网络的优化方法: 1.学习率的设置(指数衰减) 2.过拟合问题(Dropout) 3.滑动平均模型(参数更新,使模型在测试数据上更鲁棒) 4.批标准化(解决网络层数加深而产生的问题---如梯度弥散 ...

  6. Spring学习笔记:spring与mybatis四种整合方法

    1.采用数据映射器(MapperFactoryBean)的方式,不用写mybatis映射文件,采用注解方式提供相应的sql语句和输入参数.  (1)Spring配置文件: <!-- 引入jdbc ...

  7. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

  8. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  9. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

随机推荐

  1. ansible中的playbook脚本的介绍与使用

    playbook的数据结构,遵循yaml 后缀名为yaml或者yml,这两个后缀名没有区别 字典{key:value} 列表[]或者- - alex - wusir - yantao - yuchao ...

  2. Golang 实现 Redis(11): RDB 文件解析

    RDB 文件使用二进制方式存储 Redis 内存中的数据,具有体积小.加载快的优点.本文主要介绍 RDB 文件的结构和编码方式,并借此探讨二进制编解码和文件处理方式,希望对您有所帮助. 本文基于 RD ...

  3. logging日志模块详细,日志模块的配置字典,第三方模块的下载与使用

    logging日志模块详细 简介 用Python写代码的时候,在想看的地方写个print xx 就能在控制台上显示打印信息,这样子就能知道它是什么 了,但是当我需要看大量的地方或者在一个文件中查看的时 ...

  4. 用简单的 Node.js 后台程序浅析 HTTP 请求与响应

    用简单的 Node.js 后台程序浅析 HTTP 请求与响应 本文写于 2020 年 1 月 18 日 我们来看两种方式发送 HTTP 请求,一种呢,是命令行的 curl 命令:一种呢是直接在浏览器的 ...

  5. 跨云平台与物理专线使用Vxlan实现两地二层互通,并使用ospf与bgp做底层链路主备

    Vxlan基础,已掌握可略过 VXLAN网络架构 VXLAN是NVO3中的一种网络虚拟化技术,通过将原主机发出的数据包封装在UDP中,并使用物理网络的IP.MAC作为外层头进行封装,然后在IP网络上传 ...

  6. Git拉取远程新分支

    1.查看本地分支  git branch 2.查看远程分支  git branch -a 3.如果要拉取的远程分支本地没有 git fetch 4.拉取远程新分支到本地 git checkout -b ...

  7. [漏洞复现] [Vulhub靶机] Tomcat7+ 弱口令 && 后台getshell漏洞

    免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责. 0x00 背景知识 war文件 0x01 漏洞介绍 影响范围:Tomcat 8.0版本 漏洞类型:弱口令 漏洞成因:在tomc ...

  8. HTML表格以及表单

    学习内容: 1.HTML表格 代码实例: <%@ page language="java" import="java.util.*" pageEncodi ...

  9. 论文解读(LA-GNN)《Local Augmentation for Graph Neural Networks》

    论文信息 论文标题:Local Augmentation for Graph Neural Networks论文作者:Songtao Liu, Hanze Dong, Lanqing Li, Ting ...

  10. LoRa模块无线收发通信技术详解

    LoRa是一种LPWAN通信技术,它基于扩频技术而广泛应用于超长距离的无线传输场景中.现在,LoRa主要在全世界433.868.915MHz等自由频带工作.其最大特征是灵敏度高,传输距离长,工作功耗低 ...