MPI并行程序-矩阵分块乘法( Matrix multiplication : Two-Demension Method)
问题引入:
主体思路:(为了尽可能使计算简便,所有的实验矩阵均是方阵)
1. 对于A,B矩阵,首先根据子进程数p将其划分成p块形式相同的小矩阵块,其中每个矩阵块只要求是方阵即可,具体可以是1阶的,2阶的或n阶的。这里的子进程数p我采用了用于具体计算的进程数量,即除0进程以外的所有进程。划分完毕后,每个进程都持有矩阵A与矩阵B对应位置的一对儿分块阵。
2. 对A,B矩阵进行初始位置分配,这里不好用语言描述,下面三阶分块阵为例,给出示意图(因为二阶分块阵在课件中已经给出且不具一般性):
对于矩阵A
一个箭头表示移动一次,方向为左,移动完成后为
对于矩阵B
一个箭头表示移动一次,方向为上,移动完成后为
A,B位置初始化完成后,对应位置分块阵相乘,重新组合成的矩阵为C0
之后,【矩阵A所有行按上述规则左移一次,B的所有列上移一次,再对应相乘相加,得到矩阵C1】,重复步骤【】p-1次,依次得到C1,C2,,,Cn
对于上述三阶分块阵来说,将得到的C0,C1,C2相加即为所求。
各个子进程将自己求得的矩阵C的分块阵发送给进程0,汇总后即为最后的矩阵C。
程序部分关键代码(非完整)如下:
1 二维数组创建函数:
int **create_array(int row, int column, int flag, int rank)
row:行数,column:列数
flag:为1创建随机数数组,为0创建全0数组
rank:进程号,可有可无,这里用来简单的保证每个进程产生的数组不一样(进程号不一样)
2 关键变量说明:
int num_block = sqrt(size-1); //order of sub-blocks
int order_submatrix = 4 / num_block; // order of per sub-block, 4 means 4 order square matrix, also can be 9, 16,,,
int compute_times = num_block - 1; // compute times after the initially moved
3 A位置初始化:
//*********************************Initial matrixA positionif(rank > num_block ){ // limit to second row at leastint dest_A = (rank > num_block && rank % num_block == 1) ? rank + num_block - 1 : rank - 1;int source_A = (rank > num_block && rank % num_block == 0) ? rank - num_block + 1 : rank + 1;int move_times_row = (rank - 1) / num_block; // move times per rowwhile(move_times_row--){for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)sbuf[i * order_submatrix + j] = matrixA[i][j]; //write data to senfbufif(rank % order_submatrix == 1){MPI_Ssend(sbuf, order_submatrix*order_submatrix, MPI_INT, dest_A, 1, MPI_COMM_WORLD);MPI_Recv(rbuf, order_submatrix*order_submatrix, MPI_INT, source_A, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)matrixA[i][j] = rbuf[i * order_submatrix + j];}else{MPI_Recv(rbuf, order_submatrix*order_submatrix, MPI_INT, source_A, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)matrixA[i][j] = rbuf[i * order_submatrix + j];MPI_Ssend(sbuf, order_submatrix*order_submatrix, MPI_INT, dest_A, 1, MPI_COMM_WORLD);} //else} //while} //if
几个关键的地方都有注释,不再赘述。注意以下几个问题:
- 每行分块阵移动必须形成闭环,为了避免闭环资源竞争,每行第一个块(也即拥有此矩阵的进程)需单独考虑,用同步的方式先发送再接收,其他的先接收再发送。
- 确定dest时单独考虑每行第一个,确定source时单独考虑每行最后一个。
- 注意哪行移动,移动几次。
- 二维数组以一维方式发送和接收,处理起来非常简单。
4 B位置初始化:
原理同A,不放代码,自行思考。
5 C的初始化
//********************************compute the matrixC's initial position ---- C_0for(i=0; i<order_submatrix; i++){for(j=0; j<order_submatrix; j++){for(k=0; k<order_submatrix; k++)matrixC[i][j] += matrixA[i][k] * matrixB[k][j];}}
就是A与B乘法计算,然后存到C对应位置
6 对A全部行循环左移:
while(compute_times--){同上述方式进行数据传送}
7 对B全部列循环上移:
//****************shift all columns of matrixB onceint dest_B = (rank <= num_block) ? rank + (num_block - 1) * num_block : rank - num_block;int source_B = (rank > (num_block - 1) * num_block) ? rank - (num_block - 1) * num_block : rank + num_block;for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)sbuf[i * order_submatrix + j] = matrixB[i][j];if(rank <= num_block){MPI_Ssend(sbuf, order_submatrix*order_submatrix, MPI_INT, dest_B, 2, MPI_COMM_WORLD);MPI_Recv(rbuf, order_submatrix*order_submatrix, MPI_INT, source_B, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)matrixB[i][j] = rbuf[i * order_submatrix + j];}else{MPI_Recv(rbuf, order_submatrix*order_submatrix, MPI_INT, source_B, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);for(i=0; i<order_submatrix; i++)for(j=0; j<order_submatrix; j++)matrixB[i][j] = rbuf[i * order_submatrix + j];MPI_Ssend(sbuf, order_submatrix*order_submatrix, MPI_INT, dest_B, 2, MPI_COMM_WORLD);} //else
跟B初始化一样,但上面没说,这里就放一下代码,,,记得外面套个一起放到6的while大循环里,具体要单独考虑谁参考3分析
8 C的累加
上面6 和 7是一起的,同时每移动一次就要计算移动完后A与B的乘法,加上C,再对C的对应位置覆盖,就是 C += C + A * B的形式,这儿不写了。
9 数据汇总
MPI_Gather(sbuf, order_submatrix * order_submatrix, MPI_INT, rbuf, order_submatrix * order_submatrix, MPI_INT, 0, MPI_COMM_WORLD);if(rank == 0){// 输出格式处理,数据都放在rbuf里了,注意与这是矩阵块的顺序+小矩阵元素顺序,不是最后大矩阵的顺序} //if
这一部之前进程0还一直没用呢,发现没?其实这样不太好,,,管他呢。
Gather调用数据发给0进程,格式处理我就不管了
10 结果:
$mpicc -o 2Dmatrix 2Dmatrix.c -lm // parameter -lm for math.h
$ mpiexec -n 5 ./2Dmatrix
process 1 matrix A:
4 7
8 6
process 1 matrix B:
8 10
11 7
process 2 matrix A:
5 8
9 7
process 2 matrix B:
9 11
12 8
process 3 matrix A:
6 9
10 8
process 3 matrix B:
10 12
13 9
process 4 matrix A:
7 10
11 9
process 4 matrix B:
11 13
14 10
the final matrixC in process 0 is :
263 221
311 293
^^ sub-block 1 is :
287 245
341 323
^^ sub-block 2 is :
347 297
395 369
^^ sub-block 3 is :
379 329
433 407
^^ sub-block 4 is :
这是以4阶方阵,2阶分块阵,4个计算子进程(算上0进程5个)为例的,可以随意拓展成n阶分块阵,n^2个计算子进程,至于实际方阵阶数,随意1阶,2阶,3阶,,,保证每个小块是方的就行。
总结
程序原理比较简单,实现也不麻烦,基本真正思考的只有1/4,剩下的都直接复制改改就好,比如对A的行的思考跟B的列的思考差不多一样的。我认为难点只有一个,即从题目中二阶到三阶的数学推倒,题目表述不清且二阶太简单找不到规律,干瞪眼半天不会,不失一般性,写到三阶,一下子都明白了。
MPI并行程序-矩阵分块乘法( Matrix multiplication : Two-Demension Method)相关推荐
- c语言mpi并行程序,高性能计算之并行编程技术MPI并行程序设计(完整版).pdf
高性能计算之并行编程技术MPI并行程序设计(完整版) 高性能计算之并行编程技术 -- MPI并行程序设计 都志辉 编著 李三立 审阅 陈渝 刘鹏 校对 I 内容提要 本书介绍目前最常见的并行程序- M ...
- MPI并行程序编写与调试(奇偶变换排序)
MPI并行程序编写与调试(奇偶变换排序) 一.编写MPI并行计算程序 奇偶排序在多线程进行计算代码如下: 关于奇偶排序这里不做过多描述. /** File: mpi_odd_even.c* Purpo ...
- MPI并行编程: 矩阵乘法,积分计算,PSPR排序
简介 MPI(Message-Passing-Interface 消息传递接口)实现并行是进程级别的,通过通信在进程之间进行消息传递.MPI并不是一种新的开发语言,它是一个定义了可以被C.C++和Fo ...
- MPI并行程序的调试技巧
原文地址:http://galoisplusplus.gitcafe.com/blog/2013/06/08/mpi-debug-tips/ debug一个并行程序(parallel program) ...
- c语言mpi并行程序,[转]MPI并行程序的调试技巧
debug一个并行程序(parallel program)向来是件很麻烦的事情(Erlang等functional programming language另当别论),对于像MPI这种非shared ...
- MPI并行程序开发设计----------------------------------并行编程模型和算法等介绍
---------------------------------------------------------------------------------------------------- ...
- c语言mpi矩阵乘法,【MPI并行程序】矩阵乘法
具体思路为创建矩阵,给每个进程分配矩阵的不同部分,每个进程根据进程号的不同处理矩阵的不同部分,计算完成后将每个进程的数组发送给一个特定的进程,由该进程合成一个完整的矩阵输出出来.问题是不一定每个进程都 ...
- 【MPI学习3】MPI并行程序设计模式:不同通信模式MPI并行程序的设计
学习了MPI四种通信模式 及其函数用法: (1)标准通信模式:MPI_SEND (2)缓存通信模式:MPI_BSEND (3)同步通信模式:MPI_SSEND (4)就绪通信模式:MPI_RSEND ...
- Element-wise Multiplication and Matrix Multiplication
Element-wise Multiplication and Matrix Multiplication 一. Element-wise Multiplication:在python通过 *实现 1 ...
最新文章
- MediaCodeC解码视频指定帧,迅捷、精确
- 月薪没过20K的程序员要注意了!(文末送书)
- 20个开源项目托管站点推荐
- codeforces831c 思维
- dicom文件_DICOM数据转成NIfTI数据
- sql2000 中 存储过程 相关
- Product Overview page data loss handling
- Tailwind CSS 是一个工具集 CSS 框架
- [剑指offer][JAVA][第62题][约瑟夫环][LinkedList vs ArrayList]
- 安装部署gitlab ci
- VS2017安装或卸载错误1303
- tcpdump抓包最常用的命令
- PHP正则表达式(是)
- RuntimeError: view size is not compatible with input tensor‘s size and stride
- Git简洁教程:本地项目如何与GitHub互连
- Dataframe中添加一列
- springboot vue3 elementui plus小说阅读网站源码
- 动态网站如何生成静态页面
- 结构建模设计——Solidworks软件之草图绘制基础图形工具总结(绘制直线、矩形、圆、槽、圆弧、圆角等)
- [Python 高德地图] API调用学习历程(一)