MPI编程入门
一、 MPI概述
1.1 MPI的发展史
MPI标准化涉及到大约60个国家的人们,他们主要来自于美国和欧洲的40个组织,这包括并行计算机的多数主要生产商,还有来自大学、政府实验室和工厂的研究者们。1992年4月,并行计算研究中心在Williamsburg,Virginia,召开了一个关于消息传递的标准的工作会议,会议上讨论了标准消息传递的必要的、基本的特点,并建立了工作组继续进行标准化工作。
1992年10月,MPI的初步草稿MPI1形成,MPI1主要包含的是在Williamsburg工作组会议上讨论的基本消息传递的接口,因为它的基本目的就是促进讨论并继续此项工作,所以它主要集中在点对点的通信。1993年1月,第一届MPI会议在Dallas举行,1993年2月MPI1修定版本公布;之后定期召开了一系列关于MPI的核心的研讨会;1993年11月MPI的草稿和概述分别发表于Supercomputing'93和the proceedings。直到1994年5月,MPI标准正式发布。1994年7月发布了MPI标准的勘误表。
现在该工作组正在着手扩展MPI、完善MPI,从事于MPI2(MPI的扩展标准)的制定工作。
1.2 MPI的优点
●可移植性和易于使用。以低级消息传递程序为基础的较高级和(或)抽象程序所构成的分布存储通信环境中,标准化的效益特别明显。
●MPI是被正式的详细说明的:它已经成为一个标准。消息传递标准的定义能提供给生产商清晰定义的程序库,以便他们能有效地实现这些库或在某些情况下为库程序提供硬件支持,因此加强了可扩展性。
●MPI有完备的异步通信:使得nd,recieve能与计算重叠。
●可以很有效的在MPP上或Cluster上用MPI编程:MPI的虚拟拓扑反映了应用程序所申请的一组结点的通信模式,在MPP上实现的MPI便可以利用这种信息来优化处理器间的通信路径。
1.3 主要内容
●点对点通信(point_to_point communication)
●群体操作(collective operations)
●进程组(process groups)
●通信上下文(communication contexts)
●进程拓扑结构(process topologies)
cad标题栏
●与Fortran 77和C语言的邦定(bindings for Fortran 77 and C)
●环境的管理与查询(environmental management and inquiry)
●轮廓管理(profiling interface)
1.4 MPI的各种实现
在国外有许多自从MPI标准制定以来在各种机器上的MPI的portable的实现,并且他们仍从事于自己的MPI实现的性能改进,其中最著名的一些见表1。
表1 国外MPI的各种实现
XXx厕所名称 | 单 位 | 一年级学生自我评价网 址 |
CHIMP | U. of Edinburgh | ftp.epcc.ed.ac.uk/pub/chimp/. |
LAM | Ohio state | tbag.osc.edu/pub/lam/ |
MPICH | Argonne_Mississippi state | v/pub/mpi |
Unify | Mississippi state | sstate.edu/unify |
| | |
二、 MPI入门介绍
以下均以MPICH为例。
2.1 MPI的编程方式
对于基本的应用,MPI同其它消息传送系统一样易于使用。下面是一个简单的基于C语言的MPI样本代码。它是SPMD方式的,即每个进程都执行该程序,通过返回的进程编号来区分不同的进程。该程序完成进程0向进程1传递数据buf。
/
* first.c */
#include "mpi.h" /*MPI的头函数,提供基本的MPI定义和类型*/
#include <stdio.h>
int main( argc, argv )
int argc;
char **argv;
种植植物{
int rank, size, tag=333;
int buf[20]
MPI_Status status
MPI_Init( &argc, &argv ); /*MPI的初始化函数*/
MPI_Comm_rank( MPI_COMM_WORLD, &rank ); /*该进程的编号*/
MPI_Comm_size( MPI_COMM_WORLD, &size ); /*总的进程数目*/
if (rank==0)
MPI_Send( buf, 20, MPI_Int, 1, tag, MPI_COMM_WORLD); /*发送buf到进程1*/
if (rank==0)
MPI_Recv( buf, 20, MPI_Int, 0, tag, MPI_COMM_WORLD, &status); /*从进程0接收buf*/
MPI_Finalize(); /*MPI的结束函数*/
return 0;
}
2.2 MPI的基本语句介绍
1、MPI世界
进程由一个唯一的“标识数”(整数)表示,进程的标识数为数0、1、2、……、N-1。MPI_COMM_WORLD指“MPI应用中的所有进程”,它称为通信子,并且提供消息传递所需的所有信息。可移植库对通信子做更多的工作,以提供大多数其它系统所不能处理的同步保护。
2、进入和退出MPI
与其它系统一起,提供两个函数来初始化和结束MPI进程:
int MPI_Init(int *argc, char ***argv) /*初始化*/
int MPI_Finalize(void) /*结束*/
3、我是谁?他们是谁?
典型地,并行程序中的进程需要知道它是谁(它的标识数)以及其它进程是怎样存在的。一个进程通过调用MPI_Comm_rank( )来发现它自己的标识数,用MPI_Comm_size( )来返
回进程总数:
int MPI_Group_size(MPI_Group group, int *size)
int MPI_Group_rank(MPI_Group group, int *rank)
4、发送消息
消息是一组给定数据类型的元素。消息被发给一个指定的进程,而且用一个由用户说明的标识来标记。标识用来区分不同的由一个进程所能发送/接受的消息类型。
int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
5、接受消息
接受进程说明标识和发送进程的标识数。MPI_ANY_TAG和MPI_ANY_SOURCE可选地用于接受任意标识和从任意发送进程而来的消息。
int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
有关所接受消息的信息在一个状态变量status中返回。
通过这些函数,你会准备编写任意的应用。在MPI中有许多其它、更特异的函数,但是迄今为止所有这些函数可以在这里提到的函数上构造。
2.3 MPI的环境设置
在并行机上的环境一般是设置好的,不需要变动。而在NOW上运行MPI程序需要设置一些配置文件:
寝室文化标语1、 七年级下册古诗词由于加载程序到结点上运行调用了Unix系统的rsh命令,所以需要在每个结点上设置 .rhosts文件,以使rsh能正确执行;
2、 由于NOW环境的异构性,需要在启动时指定运行结点的体系结构;若未指定,是指使用与启动并行程序的结点具有相同体系结构的结点。在启动并行程序的机器里,具有相同
体系结构的几台机器的名字存放在一个名为$MPICH/util/machines/machines.<arch>的文件中,一台机器的名字占有文件的一行,其中$MPICH是一个环境变量,指明MPICH软件安装后所在的目录。并行程序加载运行时是按照文件中机器名字的先后顺序依次加载的。
2.4 MPI的编译和运行
对于简单的程序,可以使用专门的编译命令。对于大的项目,最好使用标准的Makefile。MPICH提供的编译命令有mpicc和mpif77,它们分别是C和Fortran的编译命令:
mpicc -o first first.c
mpif77 -o first firstf.f
对于编译得到的目标程序,运行的命令为:
mpirun –arch xxx –np yyy first
其中xxx为machines.<arch>的<arch>,yyy为申请的进程数目。
2.5 例子
1、 环的C语言实现
秦时明月汉时关全诗#include "mpi.h"
#include <stdio.h>
#define T_SIZE 2000
int main(argc,argv)
int argc;
char *argv[];
{
int ierr, prev, next, tag, rank, size;
MPI_Status status;
double nd_buf[T_SIZE], recv_buf[T_SIZE];
MPI_Init(&argc,&argv);
MPI_Comm_rank( MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size);
next = rank + 1;
if (next > size) next = 0;
鼓励用英语怎么说prev = rank – 1;
if (prev < 0) prev = size – 1;
if (rank == 0) {
MPI_Send(nd_buf, T_SIZE, MPI_DOUBLE, next, tag, MPI_COMM_WORLD);
MPI_Recv(recv_buf, T_SIZE, MPI_DOUBLE, prev, tag+1, MPI_COMM_WORLD, status);
} el {