华中科技大学
课程名称 并行处理
实验名称 矩阵乘法的实现及加速比分析
考生姓名 李佩佩
考生学号 M201372734
系、年级 计算机软件与理论 2013 级
类 别 硕士研究生
考试日期
2014 年 1月3日
一. 实验目的
学会如何使用集群
掌握怎么用并行或分布式的方式编程
掌握如何以并行的角度分析一个特定的问题
二. 实验环境
硬件环境: 4 核 CPU、2GB 内存计算机;
软件环境: Windows XP、 MPICH2 、 VS2010、Xmanager Enterprise3;
集群登录方式:通过远程桌面连接211.69.198.2,用户名: pppusr,密码:
AE2Q3P0。
三. 实验内容
实验代码
编写四个 .c 文件,分别为 DenseMulMatrixMPI.c 、DenseMulMatrixSerial.c、
SparseMulMatrixMPI.c 和 SparseMulMatrixSerial.c,用于比较并行和串行矩阵乘法的加速比,以及稀疏矩阵和稠密矩阵的加速比。
这里需要说明一下, 一开始的时
候我是把串、并行放在一个程序中,那么就只有两个 .c 文件 DenseMulMatrix.c
和 SparseMulMatrix.c,把串行计算矩阵乘的部分放到了主进程中,即 procsID=0 的进程,但是结果发现执行完串行后,再执行并行就特别的慢。另外,对于稀疏
矩阵的处理方面可能不太好, 在生成稀疏矩阵的过程中非 0 元素位置的生成做到
了随机化,但是在进行稀疏矩阵乘法时没有对矩阵压缩, 所以跟稠密矩阵乘法在
计算时间上没多大区别。
方阵 A 和B的初始值是利用 rand()和srand()函数随机生成的。根据稀疏矩阵和
稠密矩阵的定义,对于稀疏矩阵和稠密矩阵的初始化方法 InitMatrix( int *M, int
*N, int len)会有所不同。这里需要说明一下,一开始对于矩阵 A 和B的初始化是两
次调用 InitMatrix( int *M , int len),生成 A 和B矩阵,但是随后我发现,由于两次调用方法 InitMatrix 的时间间隔非常短, 又由于 srand()函数的特点,导致生成的矩阵
A和 B完全一样;然后,我就在两次调用之间加入了语句 “ Sleep(1000); ”,加入头文件 “#include <windows.h> ,”这样生成的 A 、B矩阵就不一样了,但很快问题又出现了,在 Xshell 中不能识别头文件 “#include <windows.h>。所”以,最后决定用下面的方法生成矩阵 A 和 B, B是A 的转置。
//稠密矩阵的生成方法
void
InitMatrix(
int
*M, int
*N,
int
len)
{
srand(( unsigned )time( NULL));
for (i=0; i < len*len; i++)
{
M[i] = rand() % 2;
}
for (i=0;i<len;i++){
for (j=0;j<len;j++){
N[i*len+j]=M[j*len+i];
}
}
}
//稀疏矩阵的生成方法
void InitMatrix( int *M, int *N, int len)
{
for (i=0;i<len*len;i++)
M[i]=0;
srand(( unsigned )time( NULL));
for (m=0;m<224;m++){
for (n=0;n<224;n++){
i=rand()%len;
j=rand()%len;
M[i*len+j]=1;
}
}
for (i=0;i<len;i++){
for (j=0;j<len;j++){
N[i*len+j]=M[j*len+i];
}
}
}
输入:并行执行的进程数 procsNum,对于串行计算,只需要 np=1;输出:程序的执行时间。
在 Windows XP 下使用 Microsoft Visual Studio2010 编程,由于稀疏矩阵和稠密矩阵的代码只是初始化部分不同, 所以以稠密矩阵乘法为例, 列出并行和串行的源代码。
并行计算的矩阵乘法源代码: DenseMulMatrixMPI.c
#include
<stdio.h>
#include
<stdlib.h>
#include
<mpi.h>
#include
<time.h>
#define
Length 1000
int
*A,*B,*C,*buffer,*ans;
int
temp,i,j,k;
int
procsID,procsNum,line;
double startTime,endTime,totalTime;
void
InitMatrix(
int
*M,
int
*N,
int len);
// 实现部分见上面
void
del(){
free(A);
free(B);
free(C);
free(buffer);
}
free(ans);
int
main(
int
argc,
char
*argv[])
{
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&procsID);
//
获取当前进程号
MPI_Comm_size(MPI_COMM_WORLD,&procsNum);
//
获取进程数目
line = Length/procsNum;
// 将数据分为(进程数)个块
A = (
int
*)malloc(
sizeof
( i