MPI并行编程实验报告.docx
《MPI并行编程实验报告.docx》由会员分享,可在线阅读,更多相关《MPI并行编程实验报告.docx(33页珍藏版)》请在冰点文库上搜索。
MPI并行编程实验报告
姓名
学号
实验
成绩
计算机系统结构
实验报告
课题:
MPI并行编程实验
起讫日期:
2012-05-20~2012-06-15
组名:
第四组
院系:
计算机学院
专业:
计算机科学与技术
指导老师:
XXX教授
2012年6月15日
实验一Linux下基于MPI的hello程序设计
Author:
姓名
一、MPICH并行计算库安装
在Linux环境下安装MPICH执行环境,配置MPD.CONF,完成实验室中临近机器间的并行配置。
概要:
以寝室四台计算机为例,设置IP(192.168.1.1~192.168.1.4),更改主机名为node01,node02,node03,node04。
(一)创建SSH信任连接
1、更改/etc/hosts文件
#vi/etc/hosts打开hosts文件,更改如下:
127.0.0.1localhost.localdomainlocalhost
192.168.1.1node01
192.168.1.2node02
192.168.1.3node03
192.168.1.4node04
2、在node01生成SSH秘钥对.
#ssh-keygen-trsa一路回车即可
产生.ssh文件,
#ls-a查看是否有.ssh文件夹
3、进入.ssh目录
#cd.ssh
4、生成authorized_keys文件
#cpid_rsa.pubauthorized_keys
5、退出到root目录
#cd..
6、建立本身的信任连接
#sshnode01按提示输入yes(三个字母要打全)
7、设置node02(node02的root目录下)
#ssh-keygen-trsa生成.ssh文件夹
#scpnode01的IP:
/root/.ssh/*/root/.ssh拷贝node01上的.ssh文件夹覆盖本地的
#scpnode01的IP:
/etc/hosts/etc/hosts拷贝node01上的hosts文件覆盖本地的
#sshnode01提示处输入yes回车
设置node03,node04的方法与node02相同
8、确认四台机器的信任连接已建立
对每个节点执行:
#sshnode01
#sshnode02
#sshnode03
#sshnode04
在提示处输入yes回车,最后确定无需输入密码并且没有任何提示信息即可登陆("Lastlogin:
时间日期"提示信息除外)
(二)安装MPICH2
1、解压缩文件包
#tar-zxvfmpich2-1.0.1.tar.gz
2、创建安装目录
#mkdir/usr/MPICH-instsll
3、进入mpich2解压目录
#cdmpich2-1.0.1
4、设置安装目录
#./configure--prefix=/usr/MPICH-install
5、编译
#make
6、安装
#makeinstall
7、退出到root目录
#cd..
8、通过编辑.bashrc文件修改环境变量
#vi.bashrc
修改后的.bashrc文件如下:
#.bashrc
#Userspecificaliasesandfunctions
aliasrm='rm-i'
aliascp='cp-i'
aliasmv='mv-i'
PATH="$PATH:
/usr/MPICH-install/bin"新增加的
#Sourceglobaldefinitions
if[-f/etc/bashrc];then
./etc/bashrc
fi
9、测试环境变量设置
#source~/.bashrc
#whichmpd
#whichmpicc
#whichmpiexec
#whichmpirun
10、修改/etc/mpd.conf文件,内容为secretword=myword
#vi/etc/mpd.conf
设置文件读取权限和修改时间
#touch/etc/mpd.conf
#chmod600/etc/mpd.conf
11、创建主机名称集合文件/root/mpd.hosts
#vimpd.hosts
文件内容如下:
node01
node02
node03
node04
(三)配置NFS
为了方便MPICH的安装及并行程序的运行,最好将MPICH的安装目录及用户家目录通过NFS网络文件系统共享。
对于仅包含几个结点的较小的集群系统,可以任意指定其中一个结点作为NFS服务器。
对较大的集群系统,应设定一个或数个结点专门用于文件服务,这些结点称为I/O结点,它们专门负责存储设备的管理,不参加计算。
这里选择node1作为NFS服务器,将它的/home和/usr/MPICH-nstall目录输出给其他三个结点,相应的配置步骤如下。
1、以root身分登录到node1上,确保node1上安装了NFS程序(nfs-utils包)。
首先运行一遍下述命令来开启NFS服务:
/sbin/chkconfignfson
/sbin/chkconfignfslockon
/etc/init.d/nfslockrestart
/etc/init.d/nfsrestart
然后编辑文件/etc/exports,在其中加入下面二行(如果该文件不存在则创建一个新文件):
/home10.0.0.0/255.255.255.248(rw,async,no_root_squash)
/usr/MPICH-install10.0.0.0/255.255.255.248(rw,async,no_root_squash)
做好上述修改后执行下面的命令:
/sbin/exportfs-a
便完成了/home和/usr/local目录的输出。
2、以root身份登录到其余三个结点,在文件/etc/fstab中加入下面两行:
node1:
/home/homenfsdefaults00
node1:
/usr/local/usr/localnfsdefaults00
并且运行一次下述命令:
/sbin/chkconfignetfson
mount-tnfs-a
完成上面的步骤后,node2,node3和node4应该共享node1的/home和/usr/MPICH-install目录。
可以在任何一个结点上用df命令来验证,例如:
#df
返回类似下面所示的结果:
......
node1:
/home2486326442240284841197428095%/home
node1:
/usr/MPICH-install2469668882008885603353307686%/usr/local
(四)环境测试
1、本地测试
#mpd&启动
#mpdtrace观看启动机器
#mpdallexit退出
2、通过mpd.hosts运行集群系统
#mpdboot-nnumber-fmpd.hostsnumber为要起动的机器个数
#mpdtrace
#mpdallexit
3、测试运行MPICH的例子程序
#mpdboot-n4-fmpd.hosts启动4台机器
#mpiexec-nnumber/usr/MPICH-install/examples/cpinumber为使用的进程数
#mpdallexit
二.HELLOWORLD并行程序设计
(一)程序源码:
/*hello.c*/
#include
#include"mpi.h"
intmain(intargc,char*argv[])
{
intrank;
intsize;
MPI_Init(0,0);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
printf("Helloworldfromprocess%dof%d\n",rank,size);
MPI_Finalize();
return0;
}
(二)程序编译
$mpicc–ohellohello.c
(三)运行结果
$mpdboot–n-fmpd.hosts
$mpiexec–n./hello
(四)实验心得:
基本上和vc运行是一样的,只是环境不一样,编译时要用mpicc–ohellohello.c运行时要用mpiexec–n./hello,错误多错几次口令也就背下来了,当让,在运行框里可以看出我刚开始忘了建自己的目录就想开始编辑程序。
实验二对等模式的MPI程序设计
Author:
姓名
一、实验目的:
掌握MPI并行程序设计的基本思想和主要编程方法,编写一个具有对等模式的MPI程序,实现各进程的对等。
二、基本概念:
所谓对等模式,就是说MPI程序的各个进程的功能、地位相同或相近,MPI程序的代码也应该是相近的,所不同的只是处理的对象和操作的数据,比如MPI程序让各个进程同时对一个数组的不同部分并行赋初值,各个进程间的关系就是典型的对等关系。
三、实验环境:
MPICH2
Windows7
四、模块说明:
Jacobi叠代
为了并行求解,这里将参加迭代的数据按列进行分割,并假设一共有4个进程同时并行计算,数据的分割结果如下图所示。
Jacobi迭代的数据划分及其与相应进程的对应
捆绑发送接收
捆绑发送和接收操作把发送一个消息到一个目的地和从另一个进程接收一个消息合并到一个调用中,源和目的可以是相同的。
捆绑发送接收操作虽然在语义上等同于一个发送操作和一个接收操作的结合,但是它可以有效地避免由于单独书写发送或接收操作时,由于次序的错误而造成的死锁。
这是因为该操作由通信系统来实现,系统会优化通信次序,从而有效地避免不合理的通信次序,最大限度避免死锁的产生。
捆绑发送接收操作是不对称的,即一个由捆绑发送接收调用发出的消息可以被一个普通接收操作接收,一个捆绑发送接收调用可以接收一个普通发送操作发送的消息。
该操作执行一个阻塞的发送和接收,接收和发送使用同一个通信域,但是可能使用不同的标识。
发送缓冲区和接收缓冲区必须分开,他们可以是不同的数据长度和不同的数据类型。
虚拟进程
虚拟进程(MPI_PROC_NULL)是不存在的假想进程,在MPI中的主要作用是充当真实进程通信的目或源,引入虚拟进程的目的是为了在某些情况下编写通信语句的方便。
当一个真实进程向一个虚拟进程发送数据或从一个虚拟进程接收数据时,该真实进程会立即正确返回,如同执行了一个空操作。
在很多情况下为通信指定一个虚拟的源或目标是非常方便的,这不仅可以大大简化处理边界的代码,而且使程序显得简洁易懂。
在捆绑发送接收操作中经常用到这种通信手段。
一个真实进程向虚拟进程MPI_PROC_NULL发送消息时会立即成功返回;一个真实进程从虚拟进程MPI_PROC_NULL的接收消息时也会立即成功返回,并且对接收缓冲区没有任何改变。
五、程序设计:
Jacobi叠代的实现
programmain
implicitnone
include'mpif.h'
integertotalsize,mysize,steps
parameter(totalsize=16)
C定义全局数组的规模
parameter(mysize=totalsize/4,steps=10)
integern,myid,numprocs,i,j,rc
reala(totalsize,mysize+2),b(totalsize,mysize+2)
C定义局部数组
integerbegin_col,end_col,ierr
integerstatus(MPI_STATUS_SIZE)
callMPI_INIT(ierr)
callMPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)
callMPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)
print*,"Process",myid,"of",numprocs,"isalive"
C数组初始化
doj=1,mysize+2
doi=1,totalsize
a(i,j)=0.0
enddo
enddo
if(myid.eq.0)then
doi=1,totalsize
a(i,2)=8.0
enddo
endif
if(myid.eq.3)then
doi=1,totalsize
a(i,mysize+1)=8.0
enddo
endif
doi=1,mysize+2
a(1,i)=8.0
a(totalsize,i)=8.0
enddo
CJacobi迭代部分
don=1,steps
C从右侧的邻居得到数据
if(myid.lt.3)then
callMPI_RECV(a(1,mysize+2),totalsize,MPI_REAL,myid+1,10,
* MPI_COMM_WORLD,status,ierr)
endif
C向左侧的邻居发送数据
if((myid.gt.0))then
callMPI_SEND(a(1,2),totalsize,MPI_REAL,myid-1,10,
* MPI_COMM_WORLD,ierr)
endif
C向右侧的邻居发送数据
if(myid.lt.3)then
callMPI_SEND(a(1,mysize+1),totalsize,MPI_REAL,myid+1,10,
* MPI_COMM_WORLD,ierr)
endif
C从左侧的邻居接收数据
if(myid.gt.0)then
callMPI_RECV(a(1,1),totalsize,MPI_REAL,myid-1,10,
* MPI_COMM_WORLD,status,ierr)
endif
begin_col=2
end_col=mysize+1
if(myid.eq.0)then
begin_col=3
endif
if(myid.eq.3)then
end_col=mysize
endif
doj=begin_col,end_col
doi=2,totalsize-1
b(i,j)=(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j))*0.25
enddo
enddo
doj=begin_col,end_col
doi=2,totalsize-1
a(i,j)=b(i,j)
enddo
enddo
enddo
doi=2,totalsize-1
print*,myid,(a(i,j),j=begin_col,end_col)
enddo
callMPI_Finalize(rc)
end
捆绑发送接收
MPI_SENDRECV(sendbuf,sendcount,sendtype,dest,sendtag,recvbuf,recvcount,
recvtype,source,recvtag,comm,status)
INsendbuf
INsendcount
INsendtype
INdest
INsendtag
OUTrecvbuf
INrecvcount
INrecvtype
INsource
INrecvtag
INcomm
OUTstatus
发送缓冲区起始地址(可选数据类型)
发送数据的个数(整型)
发送数据的数据类型(句柄)
目标进程标识(整型)
发送消息标识(整型)
接收缓冲区初始地址(可选数据类型)
最大接收数据个数(整型)
接收数据的数据类型(句柄)
源进程标识(整型)
接收消息标识(整型)
通信域(句柄)
返回的状态(status)
intMPI_Sendrecv(void*sendbuf,intsendcount,MPI_Datatypesendtype,intdest,
intsendtag,void*recvbuf,intrecvcount,MPI_Datatyperecvtype,intsource,
intrecvtag,MPI_Commcomm,MPI_Status*status)
MPI_SENDRECV(SENDBUF,SENDCOUNT,SENDTYPE,DEST,SENDTAG,
RECVBUF,RECVCOUNT,RECVTYPE,SOURCE,RECVTAG,COMM,
STATUS,IERROR)
SENDBUF(*),RECVBUF(*)
INTEGERSENDCOUNT,SENDTYPE,DEST,SENDTAG,RECVCOUNT,
RECVTYPE,SOURCE,RECVTAG,COMM,STATUS(MPI_STATUS_SIZE),IERROR
虚拟进程
programmain
implicitnone
include'mpif.h'
integertotalsize,mysize,steps
parameter(totalsize=16)
parameter(mysize=totalsize/4,steps=10)
integern,myid,numprocs,i,j,rc
reala(totalsize,mysize+2),b(totalsize,mysize+2)
integerbegin_col,end_col,ierr
integerleft,right,tag1,tag2
integerstatus(MPI_STATUS_SIZE)
callMPI_INIT(ierr)
callMPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)
callMPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)
print*,"Process",myid,"of",numprocs,"isalive"
C数组初始化
doj=1,mysize+2
doi=1,totalsize
a(i,j)=0.0
enddo
enddo
if(myid.eq.0)then
doi=1,totalsize
a(i,2)=8.0
enddo
endif
if(myid.eq.3)then
doi=1,totalsize
a(i,mysize+1)=8.0
enddo
endif
doi=1,mysize+2
a(1,i)=8.0
a(totalsize,i)=8.0
enddo
tag1=3
tag2=4
C设置当前进程左右两侧的进程标识
if(myid.gt.0)then
left=myid-1
else
left=MPI_PROC_NULL
endif
if(myid.lt.3)then
right=myid+1
else
right=MPI_PROC_NULL
endif
CJacobi迭代
don=1,steps
C从左向右平移数据
callMPI_SENDRECV(a(1,mysize+1),totalsize,MPI_REAL,right,tag1,
* a(1,1),totalsize,MPI_REAL,left,tag1,
* MPI_COMM_WORLD,status,ierr)
C从右向左平移数据
callMPI_SENDRECV(a(1,2),totalsize,MPI_REAL,left,tag2,
* a(1,mysize+2),totalsize,MPI_REAL,right,tag2,
* MPI_COMM_WORLD,status,ierr)
begin_col=2
end_col=mysize+1
if(myid.eq.0)then
begin_col=3
endif
if(myid.eq.3)then
end_col=mysize
endif
doj=begin_col,end_col
doi=2,totalsize-1
b(i,j)=(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j))*0.25
enddo
enddo
doj=begin_col,end_col
doi=2,totalsize-1
a(i,j)=b(i,j)
enddo
enddo
enddo
doi=2,totalsize-1
print*,myid,(a(i,j),j=begin_col,end_col)
enddo
callMPI_Finalize(rc)
end
实验三基于MPI计算π值
Author:
姓名
一、实验题目
用MPI技术计算π的值。
二、实验目的
熟悉MPI编程,加深对其编程的理解。
三、实验环境
WindowsXPSP3。
运行MPI
(一)安装MPI
第一步:
下载MPI软件包得到文件: