矩阵乘法MPI并行程序报告.docx
- 文档编号:8381881
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:14
- 大小:182.45KB
矩阵乘法MPI并行程序报告.docx
《矩阵乘法MPI并行程序报告.docx》由会员分享,可在线阅读,更多相关《矩阵乘法MPI并行程序报告.docx(14页珍藏版)》请在冰豆网上搜索。
矩阵乘法MPI并行程序报告
1.实验目的
1.1掌握集群的使用方法。
1.2掌握以并行的方式分析问题、设计并行程序的方法。
1.3掌握如何对并行程序进行简单的性能分析
2.实验要求
1.1使用MPI、OpenMp等并行程序设计方法设计矩阵乘法的并行程序。
1.2随机产生所需的矩阵元素,数据项不得少于1000*1000。
1.3尽量设计较高的加速比
3.实验环境
1.1硬件环境:
两个集群节点blade13、blade15。
1.2软件环境:
Linux、gcc、Win7、VC++6.0。
1.3连接方式:
XmanagerEnterprise4.0远程桌面连接211.69.198.203。
4.实验程序
1.1随机算法产生矩阵:
srand((unsignedint>time(NULL>>。
for(i=0。
i i++> { for(j=0。 j j++> { A[i][j]=rand(>%10。 B[i][j]=rand(>%10。 C[i][k]=0。 } } 1.2串行程序设计 time(&start>。 for(i=0。 i i++> { for(k=0。 k k++> { C[i][k]=0。 for(j=0。 j j++> { C[i][k]+=A[i][j]*B[j][k]。 } } } time(&end>。 1.3并行程序设计 MPI_Init(&argc,&argv> 和 MPI_Finalize(> MPI_Init用来初始化MPI执行环境,建立多个MPI进程之间的联系,为后续通信做准备。 而MPI_Finalize则是结束MPI执行环境。 这两个函数就是定义MPI程序的并行区的,除了检测是否初始化的函数之外,不应该在这两个函数定义的区域外调用其它MPI函数。 这两个函数都返回整型值,标识函数是否调用成功。 intMPI_Comm_rank(MPI_Commcomm,int*rank> MPI_Comm_rank函数用来标识各个MPI进程,获取调用该函数进程的进程号,将自身与其他进程区分。 MPI_Comm_rank返回整型的错误值,需要提供两个参数: MPI_Comm类型的通信域,标识参与计算的MPI进程组。 上面例子中使用的是MPI_COMM_WORLD,这个进程组是MPI实现预先定义好的进程组,指的是所有MPI进程所在的进程组。 如果想要申请自己的特殊的进程组,则需要通过MPI_Comm定义并通过其它MPI函数生成。 &rank返回调用进程中的标识号。 intMPI_Comm_size(MPI_Commcomm,int*size> MPI_Comm_size函数用来获取指定通信域的进程个数,确定自身需要完成的任务数。 MPI_Comm类型的通信域,标识参与计算的MPI进程组。 上面的例子中用的是MPI_COMM_WORLD。 &size返回相应进程组中的进程数。 intMPI_Send(void*buf,intcount,MPI_Datatypedatatype,intdest,inttag,MPI_Commcomm> MPI_Send函数用于发送一个消息到目标进程。 通信域中的dest进程发送数据,数据存放在buf中,类型是datatype,个数是count,这个消息的标志是tag,用以和本进程向同一目的进程发送的其它消息区别开来。 intMPI_Recv(void*buf,intcount,MPI_Datatypedatatype,intsource,inttag,MPI_Commcomm,MPI_Status*status> MPI_Recv函数用于从指定进程接收一个消息。 它的含义是进程从comm域中source进程接收标签号为tag的数据,并保存到buf中。 接收缓冲区buf的大小不能小于发送过来的消息的长度。 否则会由于数组越界导致程序出错。 主进程 if(process_id==0> { row_aver=N/slave_num。 remainder=N%slave_num。 offset=0。 for(dest=1。 dest<=slave_num。 dest++> { rows=(dest<=remainder>? row_aver+1: row_aver。 printf("sending%drowstoprocess%d\n",rows,dest>。 MPI_Send(&offset,1,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&rows,1,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&A[offset][0],rows*N,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&B,N*N,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 offset+=rows。 } start_time=MPI_Wtime(>。 for(source=1。 source<=slave_num。 source++> { MPI_Recv(&offset,1,MPI_INT,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //接收行偏移量 MPI_Recv(&rows,1,MPI_INT,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //接收行数 MPI_Recv(&C[offset][0],rows*N,MPI_UNSIGNED_LONG_LONG,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //C接收从进程发回的结果 } end_time=MPI_Wtime(>。 printf("processcost%fseconds\n",end_time-start_time>。 } 从进程 if(process_id>0> { MPI_Recv(&offset,1,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&rows,1,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&A,rows*N,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&B,N*N,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 //矩阵乘法 for(i=0。 i i++> { for(k=0。 k k++> { inttmp=A[i][k]。 for(j=0。 j j++> { C[i][j]+=tmp*B[k][j]。 //利用 } } } MPI_Send(&offset,1,MPI_INT,0,FROM_SLAVE,MPI_COMM_WORLD>。 MPI_Send(&rows,1,MPI_INT,0,FROM_SLAVE,MPI_COMM_WORLD>。 MPI_Send(&C,rows*N,MPI_UNSIGNED_LONG_LONG,0,FROM_SLAVE,MPI_COMM_WORLD>。 } MPI_Finalize(>。 return0。 } 5.性能分析 分析公式: 加速比=串行执行时间/并行执行时间 效率=加速比/节点数 1.1串行程序的执行时间<秒) 矩阵规模 实验结果 1000 2000 3000 4000 第1次 11.000 99.000 372.000 799.000 第2次 11.000 98.000 376.000 799.000 第3次 11.000 99.000 373.000 802.000 平均值 11.000 98.667 373.667 800.000 图1.不同矩阵规模下串行程序的执行时间 1.2八个节点时,不同矩阵规模并行程序的执行时间<秒) 矩阵规模 实验结果 1000 2000 3000 4000 第1次 0.829 6.833 23.372 55.422 第2次 0.832 6.838 23.315 55.786 第3次 0.837 6.820 23.560 55.732 平均值 0.833 6.830 23.416 55.647 加速比 13.205 14.446 15.958 14.376 效率 1.651 1.806 1.995 1.797 图2.八个节点时,不同矩阵规模下并行程序的执行时间 图3.八个节点时,不同矩阵规模下并行程序的加速比 图4.八个节点时,不同矩阵规模下并行程序的效率 分析 随着矩阵规模的增加 执行时间 程序的执行时间急剧增加。 加速比 程序的加速比基本保持不变。 效率 程序的效率基本保持不变。 1.3矩阵规模为1000*1000时,不同节点数下并行程序的执行时间<秒) 节点个数 实验结果 2 3 4 5 6 7 8 第1次 5.792 2.917 1.945 1.455 1.170 0.973 0.829 第2次 5.793 2.899 1.944 1.474 1.167 0.971 0.832 第3次 5.838 2.915 1.935 1.453 1.169 0.975 0.837 平均值 5.808 2.910 1.941 1.461 1.169 0.973 0.833 加速比 1.984 3.780 5.667 7.259 9.410 11.305 13.205 效率 0.992 1.260 1.417 1.452 1.568 1.615 1.651 图5.矩阵规模1000*1000时,不同节点下的并行程序的执行时间 图6.矩阵规模1000*1000时,不同节点下的并行程序的加速比 图7.矩阵规模1000*1000时,不同节点下的并行程序的效率 分析 随着计算节点数的增加, 执行时间 程序的执行时间迅速减少,然后趋于平稳。 加速比 程序的加速比基本呈线性增长,公式趋y=1.8374x+0.022。 效率 程序的效率逐步增长,然后趋于平缓。 6.用户手册 1.1连接: sshpppusr@211.69.168.203密码: ****** 1.2登陆: sudosshblade13或者blade15 1.3切换至工作目录: cd/home/pppusr/***** 1.4编译: mpicc-omatrixmatrix_multi.c 1.5运行: mpirun-np8./matrix #include #include #include #defineN1000 #defineFROM_MASTER1 #defineFROM_SLAVE2 intA[N][N],B[N][N]。 unsignedlonglongC[N][N]。 MPI_Statusstatus。 //消息接收状态变量,存储也是分布的 intmain(intargc,char**argv> { intprocess_num。 //进程数,该变量为各处理器中的同名变量,存储是分布的 intprocess_id。 intslave_num。 intdest。 //目的进程标识号 intsource。 //发送数据进程的标识号 introws。 introw_aver。 intremainder。 intoffset。 //行偏移量 inti,j,k。 doublestart_time,end_time。 srand((unsignedint>time(NULL>>。 for(i=0。 i i++> { for(j=0。 j j++> { A[i][j]=rand(>%10。 B[i][j]=rand(>%10。 C[i][k]=0。 } } MPI_Init(&argc,&argv>。 //初始化MPI /*该函数被各进程各调用一次,得到各自的进程id值*/ MPI_Comm_rank(MPI_COMM_WORLD,&process_id>。 /*该函数被各进程各调用一次,得到进程数*/ MPI_Comm_size(MPI_COMM_WORLD,&process_num>。 slave_num=process_num-1。 if(process_id==0> { row_aver=N/slave_num。 remainder=N%slave_num。 offset=0。 //有的程序是将时间函数放在这个for循环的两边 for(dest=1。 dest<=slave_num。 dest++> { rows=(dest<=remainder>? row_aver+1: row_aver。 printf("sending%drowstoprocess%d\n",rows,dest>。 MPI_Send(&offset,1,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&rows,1,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&A[offset][0],rows*N,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 MPI_Send(&B,N*N,MPI_INT,dest,FROM_MASTER,MPI_COMM_WORLD>。 offset+=rows。 } start_time=MPI_Wtime(>。 for(source=1。 source<=slave_num。 source++> { MPI_Recv(&offset,1,MPI_INT,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //接收行偏移量 MPI_Recv(&rows,1,MPI_INT,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //接收行数 MPI_Recv(&C[offset][0],rows*N,MPI_UNSIGNED_LONG_LONG,source,FROM_SLAVE,MPI_COMM_WORLD,&status>。 //C接收从进程发回的结果 } end_time=MPI_Wtime(>。 printf("processcost%fseconds\n",end_time-start_time>。 } if(process_id>0> { MPI_Recv(&offset,1,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&rows,1,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&A,rows*N,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 MPI_Recv(&B,N*N,MPI_INT,0,FROM_MASTER,MPI_COMM_WORLD,&status>。 for(i=0。 i i++> { for(k=0。 k k++> { inttmp=A[i][k]。 for(j=0。 j j++> { C[i][j]+=tmp*B[k][j]。 } } } MPI_Send(&offset,1,MPI_INT,0,FROM_SLAVE,MPI_COMM_WORLD>。 //将行偏移量发回主进程 MPI_Send(&rows,1,MPI_INT,0,FROM_SLAVE,MPI_COMM_WORLD>。 //将行数发回主进程 MPI_Send(&C,rows*N,MPI_UNSIGNED_LONG_LONG,0,FROM_SLAVE,MPI_COMM_WORLD>。 //将计算得到的值发回主进程 } /*关闭MPI,标志并行代码段的结束*/ MPI_Finalize(>。 return0。 } 申明: 所有资料为本人收集整理,仅限个人学习使用,勿做商业用途。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 矩阵 乘法 MPI 并行 程序 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)