并行计算 - hw3
一、个人信息
| 条目 | 内容 |
|---|---|
| 学号 | xxxxx |
| 姓名 | Thyrsael |
| 学院 | 计算机学院 |
| JobID | 7995268 |
二、实验过程
首先用矩阵生成程序生成 和 两个矩阵
./matrixgen 1200 1600 matrixA |
然后用串行程序进行计算求得时间,需要注意的是开启了 O2 编译优化以减小常数使结果更为客观
gcc -o tserial -O2 ./Tserial.cxx |
输出为
Serial algrithm: multiply a 1200x1600 with a 1600x2000, use 16.8556230068(s) |
然后采用并行程序进行计算,依然需要开启 O2 优化,最后结果为
--- 1600 x 1200 x 2000 matrix number procs: 32 time: 1.6867085472(s) --- |
实验截图如下

验证两个计算结果的一致性
cmp matrixPC matrixSC |
发现结果一致,检验了程序的正确性。
最后计算加速比
可以看到加速了近 10 倍,足以见到并行计算的威力。
三、流程分析
3.1 泳道图

采用的是广播模式,所以与提供的源码(为点对点通信)显示的流程差异较大,我会在下面介绍具体的算法。
3.2 源码错误分析
死锁问题

在这里,没有考虑到当 numprocs > M 的情况,这会导致主进程没有给 id >= M 的进程发送任何信息 这些进程会一直处于等待中,造成死锁。
---1600x1200x2000 matrix number procs: 32 time: 2.5864(s)--- |
如果采用原有代码的架构,可以考虑给 id >= M 的进程发送一条 “约定信息”,当这些进程收到 “约定信息” 的时候,就会自动退出,不会造成死锁。大致如下
// 主进程 |
再分配问题

这里再次发送的 的行,不再是 i - 1 ,而应该是 numsend。只有这样才可以将剩余的行逐行分发。可以考虑如下修改
MPI_Send(A + numsend * N, N, MPI_DOUBLE, sender, 99, MPI_COMM_WORLD); |
释放资源问题
从进程没有释放这两个分配空间(补上即可)
free(A_row); |
3.3 源码性能分析
点对点通信
点对点的通信代价过大,如果用广播形式会优化传播的效率,因为节点的通信形式可以变成网状或者树状。
定长数组

因为此题改成了从文件中读出矩阵,在读出之前, 的维度信息是不知道的。如果想使用定长数组,就必须要将其两个维度都赋一个极大的值,这就导致了在通信的时候传输的数据过大(每次都要传输一个大于实际矩阵的数组),造成了性能的低下。
可以考虑用 malloc 和宏来动态分配和访存,如下所示
/** |
在使用的时候,可以这样使用
// C[i][j] += A[i][k] * B[k][j]; |
通信流程
该程序的流程是多次分发的,首先给每个进程都分发一行,这是一个顺序过程,而不是一个并行的,这是第一个性能损失,如下所示
// 串行发送 |
而且这次分发并没有结束,这就导致了再次需要通信的需求,这是第二个性能损失。
而且第二次分发必须要等到第一次分发顺序结束之后才可以继续分发,这就导致了分发的串行化,可能第 5 个进程早就完成了第一次的任务,但是必须等到前 4 个进程都领到第二次的任务,才可以领到第二次的任务。这导致了第三个性能损失。如下所示:
// 第二次分发,造成了损失 |
正是因为有了上面的诸多问题,才有了新的模式的开发。
3.4 Scatter-Gather 模式
3.4.1 原理介绍
MPI_Scatter 和 MPI_Gather 都是 MPI 广播函数,其签名如下
MPI_Scatter( |
其实例图如下


在并行矩阵乘法中,我们利用 MPI_Scatter 进行对矩阵 进行块状(block)划分,如图所示:

对于大部分的矩阵 ,都可以均匀的分配给每个进程,对于无法均分的部分,最后将有主进程处理。还有一种思路是对于 进行行补零操作,使其变成一个可以均匀分配的矩阵。但是依然需要主进程操作。
3.4.2 问题解决
死锁错误
当 numprocs > M 的时候,原有程序会死锁,但是在新的程序中,这只会导致主进程自己进行计算,分发的矩阵大小为 0,每个进程都会收到大小为 0 的局部矩阵,所以不会死锁。,如下所示
// 利用的是向下取整,那么有可能 localM * numprocs < M,也就是 A 矩阵没有被分配完 |
再分配错误
只需要一次分配,所以自然没有再分配错误。
点对点通信优化
抛弃了点对点通信,采用了广播通信的形式,这就使得信息的传递路径更短,复用率更高。
通信流程优化
完全消除了之前源码中的形式,可以简洁优雅的进行单次通信,进程间的串行减少。
四、结果分析
4.1 线程问题
我们利用混合编程,利用了线程,所以最好将节点的数目调大,这样每个进程分布在不同的节点上,每个进程都可以利用其节点上的多个处理器核,达到加速的目的。
4.2 广播模式优化
借来小组同学的用 Send-Recv 程序进行测试,发现相同条件下(32 node,32 core,[1200 x 1600] x [1600 x 2000]),其时间为
time: 2.1495252177(s) |
所以 Scatter-Gather 模式相对于 Send-Recv 程序的加速比为
可以看到还是有一定优化效果的。
五、程序源码
|