MPI用户手册.docx
《MPI用户手册.docx》由会员分享,可在线阅读,更多相关《MPI用户手册.docx(82页珍藏版)》请在冰点文库上搜索。
MPI用户手册
MPI用户手册
神威Ⅰ计算机系统
MPI培训手册
国家并行计算机工程技术研究中心
二零零零年八月
第一章MPI简介
MPI(MessagePassingInterface)是1994年5月发布的一种消息传递接口。
它实际上是一个消息传递函数库的标准说明,吸取了众多消息传递系统的优点,是目前国际上最流行的并行编程环境之一,尤其是分布式存储的可缩放并行计算机和工作站网络的一种编程范例。
MPI具有许多优点:
具有可移植性和易用性;有完备的异步通信功能;有正式和详细的精确定义,固而为并行软件产业的增长提供了必要的条件。
在基于MPI编程模型中,计算是由一个或多个彼此通过调用库函数进行消息收、发通信的进行所组成。
在绝大部分MPI实现中,一组固定的进程在程序初始化时生成,一个处理器生成一个进程。
这些进程可以执行相同或不同的程序(相应地称为SPMD或MPMD模式)。
进程间地通信可以是点到点的,也可以是集合的。
MPI只是为程序员提供一个并行环境库,程序员通过调用MPI的库程序来达到程序员所要达到的并行目的。
MPI提供C语言接口和Fortran语言接口。
一个简单例子:
#include“mpi.h”
main(intargc,char**argv)
{
intmyrank,i,j,k;
MPI_Statusstatus;
charmsg[20];
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
if(myrank==0){
strcpy(msg,”Hellothere”);
MPI_Send(msg,strlen(msg)+1,MPI_CHAR,1,99,MPI_COMM_WORLD);
}elseif(myrank==1){
MPI_Recv(msg,20,MPI_CHAR,0,99,MPI_COMM_WORLD,&status);
}
MPI_Finalize();
}
1.1名词解释
1.1.1分布式内存
每个CPU都有自己的私有存储空间,数据从一个处理器到另一个处理器只有通过网络来传输,而共享存储中的多个CPU可同时访问同一内存单元。
分布式系统的示意图如下:
1.1.2消息传输
消息传输是消息数据从一个处理器的内存拷贝到另一个处理器内存的方法。
在分布式存储系统中,数据通常是以消息包的形式通过网络从一个处理器发送到另一个处理器,在消息包中,包含了消息头控制信息及消息体数据信息两部分。
1.1.3进程
进程是运行在一个处理器上的一个程序,多个进程可运行在同一个处理器上。
在消息传递系统中,即使是在同一个处理器中运行的多个进程,他们之间的数据通讯也是通过消息传输来实现的。
为了提高效率,在消息传递系统中,一般一个处理器只运行一个进程。
1.1.4消息传递库
可连接到用户应用程序中实现消息发送、消息接收以及其他消息传递操作的一组函数的集合。
1.1.5发送/接收
消息通信包括数据传输从一个进程(发送)到另一个进程(接收)。
这就要求两个进程协作完成消息发送和接收过程,发送进程一般要求指定发送数据的源、数据长度、数据类型及目的地,而接收操作也要求指定相应的操作与发送相匹配。
1.1.6同步/异步
同步发送操作只有等到消息被接收进程安全接收后才完成,而异步发送操作完成后消息不一定被接收进程接收。
1.1.7阻塞通讯
阻塞通讯调用完成是否完成依靠某些“事件”:
对于阻塞发送,数据必须成功的发送或被拷贝到系统缓冲区,使得该数据缓冲区可被重新使用;对于阻塞接收,数据必须保证正确接收到本地缓冲区。
1.1.8非阻塞通讯
非阻塞通讯不等待任何通讯事件就可以完成,它不保证数据已正确发送或接收。
发送或接收得数据也许在源方,也许正在网上,也许已经到目的方。
1.1.9应用程序缓冲区
在用户应用程序中定义的用于保存发送和接收数据的地址空间。
1.1.10系统缓冲区
保留消息的系统空间。
在异步通讯的条件下,一般需要把数据从应用程序缓冲区中拷贝到系统缓冲区,保证用户数据不被覆盖。
1.2MPI环境简介
1.2.1头文件
要求所有包含MPI调用得程序文件应加入:
C包含文件
Fortran包含文件
#include“mpi.h”
include‘mpif.h’
1.2.2MPI调用格式
C程序区分大小写,Fortran程序不区分大小写
C程序
格式:
rc=MPI_Xxxxx(parameter,...)
例子:
rc=MPI_Bsend(&buf,count,type,dest,tag,comm)
错误码:
如果调用成功则rc返回MPI_SUCCESS
Fortran程序
格式:
CALLMPI_XXXXX(parameter,...,ierr)
callmpi_xxxxx(parameter,...,ierr)
例子:
CALLMPI_BSEND(buf,count,type,dest,tag,comm,ierr)
错误码:
如果调用成功则ierr返回MPI_SUCCESS
1.2.3
一般MPI程序结构
.
.
.
.
.
.
.
1.2.4通信因子和组
MPI通过指定通信因子和组来完成各个进程间得通信,大多数MPI调用要求加入通信因子这个参数。
MPI_COMM_WORLD通信因子是在MPI环境初始化过程中创建地包含了所有进程,也是最重要的一个通信因子。
详细的用法下面再介绍。
1.2.5秩
在一个通信因子中,每个进程都有一个唯一的整数标识符,该标识符在MPI初始化时创建,有时也称作“进程ID”,秩是从0开始的连续整数。
在用户程序中,经常用秩来判断程序的运行方向。
如:
if(rank==0){
dothis
}elseif(rank==1){
dothat
}
第二章MPI环境管理调用
2.1函数调用
2.1.1MPI_Init
初始化MPI运行环境。
每个MPI程序必须调用这个函数,并且这个函数必须在所有调用MPI函数之前调用,而且只能调用一次。
对于C程序,MPI_Init必须传递所有的命令行参数:
MPI_Init(*argc,*argv)
MPI_INIT(ierr)
2.1.2MPI_Comm_size
该函数返回与该组通信因子相关的进程数,通常可以根据通信因子MPI_COMM_WORD来查询用户程序包含的进程数:
MPI_Comm_size(comm,*size)
MPI_COMM_SIZE(comm,size,ierr)
2.1.3MPI_Comm_rank
该函数返回该进程在指定通信因子中的秩(0~进程数-1),一个进程在不同通信因子中的秩可能不同:
MPI_Comm_rank(comm,*rank)
MPI_COMM_RANK(comm,rank,ierr)
2.1.4MPI_Abort
结束所有与该通信因子相关的进程,但一般来说,调用该函数后,所有的进程都退出,不管该进程是否与该通信因子相关:
MPI_Abort(comm,errorcode)
MPI_ABORT(comm,errorcode,ierr)
2.1.5MPI_Get_processor_name
返回该进程所在处理器的名称,该名称根据网络地址命名地,name缓冲区的大小必须大于MPI_MAX_PROCESSOR_NAME,真正的长度返回在resultlength变量中:
MPI_Get_processor_name(*name,*resultlength)
MPI_GET_PROCESSOR_NAME(name,resultlength,ierr)
2.1.6MPI_Initialized
判断MPI_Init是否被执行,返回true
(1),false(0),MPI应用程序只允许每一个进程仅运行一次MPI_Init:
MPI_Initialized(*flag)
MPI_INITIALIZED(flag,ierr)
2.1.7MPI_Wtime
返回调用进程已经执行过地时间,以秒为单位,双精度:
MPI_Wtime()
MPI_WTIME()
2.1.8MPI_Wtick
按秒返回MPI_Wtime的分辨率,也就是返回一个双精度值(连续时间之间的秒数)。
例如,如果时钟由作为按毫秒递增的计数器实现,则MPI_Wtick返回的值是10-3。
MPI_Wtick()
MPI_WTICK()
2.1.9MPI_Finalize
结束MPI执行环境。
该函数一旦被应用程序调用时,就不能调用MPI的其它例行函数(包括MPI_Init),用户必须保证在进程调用MPI_Finalize之前把与完成进程有关的所有通信结束。
MPI_Finalize()
MPI_FINALIZE(ierr)
2.2MPI环境管理例子
2.2.1C语言例子:
#include"mpi.h"
#include
intmain(argc,argv)
intargc;
char*argv[];
{
intnumtasks,rank,rc;
rc=MPI_Init(&argc,&argv);
if(rc!
=0){
printf("ErrorstartingMPIprogram.Terminating.\n");
MPI_Abort(MPI_COMM_WORLD,rc);
}
MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
printf("Numberoftasks=%dMyrank=%d\n",numtasks,rank);
/*******dosomework*******/
MPI_Finalize();
}
2.2.2Fortran语言例子
programsimple
include'mpif.h'
integernumtasks,rank,ierr,rc
callMPI_INIT(ierr)
if(ierr.ne.0)then
print*,'ErrorstartingMPIprogram.Terminating.'
callMPI_ABORT(MPI_COMM_WORLD,rc,ierr)
endif
callMPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr)
callMPI_COMM_SIZE(MPI_COMM_WORLD,numtasks,ierr)
print*,'Numberoftasks=',numtasks,'Myrank=',rank
C******dosomework******
callMPI_FINALIZE(ierr)
end
第三章点对点通信函数
3.1参数说明
3.1.1MPI消息传递函数参数
MPI点对点通信函数的参数格式一般如下所示:
阻塞发送
MPI_Send(buffer,count,type,dest,tag,comm)
非阻塞发送
MPI_Isend(buffer,count,type,dest,tag,comm,request)
阻塞接收
MPI_Recv(buffer,count,type,source,tag,comm,status)
非阻塞接收
MPI_Irecv(buffer,count,type,source,tag,comm,request)
3.1.2缓冲区(buffer)
指应用程序定义地用于发送或接收数据的缓冲区。
3.1.3数据个数(count)
指发送或接收指定数据类型的个数。
3.1.4数据类型(type)
MPI定义了一些缺省的数据类型,用户也可以根据需要建立自己的数据类型,其中MPI_BYTE和MPI_PACKED与C或Fortran语言的类型不对应:
MPIC语言数据类型
MPIFortran语言数据类型
MPI_CHAR
signedchar
MPI_CHARACTER
character
(1)
MPI_SHORT
signedshortint
MPI_INT
signedint
MPI_INTEGER
integer
MPI_LONG
signedlongint
MPI_UNSIGNED_CHAR
unsignedchar
MPI_UNSIGNED_SHORT
unsignedshortint
MPI_UNSIGNED
unsignedint
MPI_UNSIGNED_LONG
unsignedlongint
MPI_FLOAT
float
MPI_REAL
real
MPI_DOUBLE
double
MPI_DOUBLE_PRECISION
doubleprecision
MPI_LONG_DOUBLE
longdouble
MPI_COMPLEX
complex
MPI_LOGICAL
logical
MPI_BYTE
8binarydigits
MPI_BYTE
8binarydigits
MPI_PACKED
datapackedor
unpackedwith
MPI_Pack()/
MPI_Unpack
MPI_PACKED
datapackedor
unpackedwith
MPI_Pack()/
MPI_Unpack
3.1.5目的地(dest)
发送进程指定的接收该消息的目的进程,也就是接收进程的秩。
3.1.6源(source)
接收进程指定的发送该消息的源进程,也就是发送进程的秩。
如果该值为MPI_ANY_SOURCE表示接收任意源进程发来的消息。
3.1.7标识符(tag)
由程序员指定地为标识一个消息的唯一非负整数值(0-32767),发送操作和接收操作的标识符一定要匹配,但对于接收操作来说,如果tag指定为MPI_ANY_TAG则可与任何发送操作的tag相匹配。
3.1.8通信因子(comm)
包含源与目进程的一组上下文相关的进程集合,除非用户自己定义(创建)了新的通信因子,否则一般使用系统预先定义的全局通信因子MPI_COMM_WORLD。
3.1.9状态(status)
对于接收操作,包含了接收消息的源进程(source)和消息的标识符(tag)。
在C程序中,这个参数是指向MPI_Status结构的指针(如:
status.MPI_SOURCE、status.MPI_TAG);在Fortran程序中,这个参数是大小为MPI_STATUS_SIZE的整数矩阵(如:
status(MPI_SOURCE)、status(MPI_TAG))。
另外,实际接收到的消息长度可以通过MPI_Get_count()函数从该参数中得到。
3.1.10请求(request)
这个参数用于非阻塞发送和非阻塞接收操作。
由于非阻塞操作返回后,消息实际上还没有完成到达真正发送或接收,因此用户可以根据该变量调用其它函数完成消息的实际发送和接收。
在C程序中,这个参数是指向MPI_Request结构的指针;在Fortran程序中,这个参数是一个整数。
3.2阻塞消息通信函数
这里介绍一些最主要的阻塞消息通信函数:
3.2.1MPI_Send
该函数是最基本的阻塞发送函数。
当函数返回时,应用程序的发送缓冲区空闲,可以继续使用。
MPI_Send(*buf,count,datatype,dest,tag,comm)
MPI_SEND(buf,count,datatype,dest,tag,comm,ierr)
3.2.2MPI_Recv
阻塞接收消息,直到该消息到达本进程的接收缓冲区后才返回。
MPI_Recv(*buf,count,datatype,source,tag,comm,*status)
MPI_RECV(buf,count,datatype,source,tag,comm,status,ierr)
3.2.3MPI_Ssend
同步阻塞发送:
发送一个消息,直到发送进程的缓冲区空闲并且接收进程已经开始接收该消息后返回
MPI_Ssend(*buf,count,datatype,dest,tag,comm,ierr)
MPI_SSEND(buf,count,datatype,dest,tag,comm,ierr)
3.2.4MPI_Bsend
缓冲区阻塞发送:
应用程序首先应申请一个足够大的缓冲区,然后用MPI_Buffer_attach函数加以确认,当MPI_Bsend函数返回时,消息数据已经从应用程序发送缓冲区拷贝到分配的缓冲区中。
MPI_Bsend(*buf,count,datatype,dest,tag,comm)
MPI_BSEND(buf,count,datatype,dest,tag,comm,ierr)
3.2.5MPI_Buffer_attach、MPI_Buffer_detach
用于分配和释放用于MPI_Bsend函数的发送缓冲区,size参数是以字节为计的缓冲区大小:
MPI_Buffer_attach(*buffer,size)
MPI_Buffer_detach(*buffer,size)
MPI_BUFFER_ATTACH(buffer,size,ierr)
MPI_BUFFER_DETACH(buffer,size,ierr)
3.2.6MPI_Rsend
预备方式的阻塞发送。
如果能确认接收进程已经开始匹配接收时,可以使用该发送函数:
MPI_Rsend(*buf,count,datatype,dest,tag,comm)
MPI_RSEND(buf,count,datatype,dest,tag,comm,ierr)
3.2.7MPI_Sendrecv
阻塞发送并阻塞接收一个消息。
只有当发送缓冲区空并接收缓冲区消息有效后该函数才返回:
MPI_Sendrecv(*sendbuf,sendcount,sendtype,dest,sendtag,
*recvbuf,recvcount,recvtype,source,recvtag,
comm,*status)
MPI_SENDRECV(sendbuf,sendcount,sendtype,dest,sendtag,
recvbuf,recvcount,recvtype,source,recvtag,
comm,status,ierr)
3.2.8MPI_Wait、MPI_Waitany、MPI_Waitall、MPI_Waitsome
MPI_Wait函数只有当指定的消息发送或接收完成后才返回,对于多个非阻塞的操作,程序员可以指定任何一个或一些或全部的消息发送或接收完成后再返回:
MPI_Wait(*request,*status)
MPI_Waitany(count,*array_of_requests,*index,*status)
MPI_Waitall(count,*array_of_requests,*array_of_statuses)
MPI_Waitsome(incount,*array_of_requests,*outcount,array_of_offsets,*array_of_statuses)
MPI_WAIT(request,status,ierr)
MPI_WAITANY(count,array_of_requests,index,status,ierr)
MPI_WAITALL(count,array_of_requests,array_of_statuses,ierr)
MPI_WAITSOME(incount,array_of_requests,outcount,
array_of_offsets,array_of_statuses,ierr)
3.2.9MPI_Probe
该函数探测一个消息是否完成接收,只有当探测到消息接收完成后才返回:
MPI_Probe(source,tag,comm,*status)
MPI_PROBE(source,tag,comm,status,ierr)
3.3阻塞消息传递例子
3.3.1C程序例子
#include"mpi.h"
#include
intmain(argc,argv)
intargc;
char*argv[];
{
intnumtasks,rank,dest,source,rc,tag=1;
charinmsg,outmsg='x';
MPI_StatusStat;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if(rank==0){
dest=1;
source=1;
rc=MPI_Send(&outmsg,1,MPI_CHAR,dest,tag,MPI_COMM_WORLD);
rc=MPI_Recv(&inmsg,1,MPI_CHAR,source,tag,MPI_COMM_WORLD,&Stat);
}elseif(rank==1){
dest=0;
source=0;
rc=MPI_Recv(&inmsg,1,MPI_CHAR,source,tag,MPI_COMM_WORLD,&Stat);
rc=MPI_Send(&outmsg,1,MPI_CHAR,dest,tag,MPI_COMM_WORLD);
}
MPI_Finalize();
}
3.3.2Fortran程序例子
programping
include'mpif.h'
integernumtasks,rank,dest,source,tag,ierr
integerstat(MPI_STATUS_SIZE)
characterinmsg,outmsg
tag=1
callMPI_INIT(ierr)
callMPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr)
callMPI_COMM_SIZE(MPI_COMM_WORLD,numtasks,ierr)
if(rank.eq.0)then
dest=1
source=1
outms