44
MPI MPI 分分分分分分 分分分分分分 分分分分 分分分分

MPI 分布内存并行 程序开发

  • Upload
    gwylan

  • View
    105

  • Download
    0

Embed Size (px)

DESCRIPTION

MPI 分布内存并行 程序开发. 第一章. 并行计算概述. 为什麽要采用并行计算?. 串行程序速度提升缓慢 可以加快速度——更短的时间内解决相同的问题;相同的时间内解决更多更复杂的问题 可以加大规模——计算更大规模的问题. 并行计算设计的分类. 共享内存 ccNUMA; SMP 分布式内存 MPP; Cluster. 三种计算模型. 并行化分解方法. 任务分解 多任务并发执行 功能分解 分解被执行的计算 区域分解 分解被执行的数据. 分布内存并行方式. 任务并行 - PowerPoint PPT Presentation

Citation preview

Page 1: MPI 分布内存并行 程序开发

MPIMPI 分布内存并行分布内存并行程序开发程序开发

Page 2: MPI 分布内存并行 程序开发

22

第一章第一章

并行计算概述并行计算概述

Page 3: MPI 分布内存并行 程序开发

33

为什麽要采用并行计算为什麽要采用并行计算 ??

串行程序速度提升缓慢串行程序速度提升缓慢 可以加快速度——更短的时间内解决相可以加快速度——更短的时间内解决相

同的问题;相同的时间内解决更多更复同的问题;相同的时间内解决更多更复杂的问题杂的问题

可以加大规模——计算更大规模的问题可以加大规模——计算更大规模的问题

Page 4: MPI 分布内存并行 程序开发

44

并行计算设计的分类并行计算设计的分类

共享内存共享内存 ccNUMA; SMPccNUMA; SMP

分布式内存分布式内存 MPP; ClusterMPP; Cluster

Page 5: MPI 分布内存并行 程序开发

55

三种计算模型三种计算模型

Page 6: MPI 分布内存并行 程序开发

66

并行化分解方法并行化分解方法

任务分解任务分解 多任务并发执行多任务并发执行

功能分解功能分解 分解被执行的计算分解被执行的计算

区域分解区域分解 分解被执行的数据分解被执行的数据

Page 7: MPI 分布内存并行 程序开发

77

分布内存并行方式分布内存并行方式

任务并行任务并行 不同参数的大量工况计算不同参数的大量工况计算

区域分解并行区域分解并行 大规模多节点分块并行计算大规模多节点分块并行计算

Page 8: MPI 分布内存并行 程序开发

88

第二章 第二章 MPIMPI 简介简介MPI(Message Passing Interface ) 是 1994 年 5月发布的一种消息传递接口。它实际上是一个消息传递函数库的标准说明,以语言独立的形式来定义这个接口库 , 并提供了与 C 和 Fortran 语言的绑定 . 。

Page 9: MPI 分布内存并行 程序开发

99

MPIMPI 的历史的历史

MPIMPI 初稿初稿 :: 美国并行计算中心工作会议(美国并行计算中心工作会议( 9922 年年 44 月)月)

MPI-1MPI-1 公布:第一届公布:第一届 MPIMPI 大会(大会( 9393 年年 11月);月);

MPIMPI 标准正式发布:标准正式发布: 19941994 年年 55 月;月; MPI-2MPI-2 发布:发布: MPIMPI 论坛(论坛( 9797 年)。年)。

Page 10: MPI 分布内存并行 程序开发

1010

MPICH :最重要的 MPI 实现( www-unix.mcs.anl.gov/mpi/ mpich ),与 MPI-1 规范同步发展的版本,支持部分 MPI-2 的特征如动态生成进程等。

CHIMP : EPCC(Edinburgh Parallel Computing Center) 开发。 ftp://ftp.epcc.ed.ac.uk/pub/packages/chimp/release 下载。

LAM(Local Area Multicomputer) : Ohio State University开发。 http://www.lam-mpi.org/download/ 下载。

MPI 的实现

Page 11: MPI 分布内存并行 程序开发

1111

第三章 第三章 MPIMPI 编程编程

Page 12: MPI 分布内存并行 程序开发

1212

MPI 为程序员提供一个并行环境库,程序员通过调用 MPI的库程序来达到程序员所要达到的并行目的,可以只使用其中的 6 个最基本的函数就能编写一个完整的 MPI 程序去求解很多问题。这 6 个基本函数,包括启动和结束 MPI 环境,识别进程以及发送和接收消息:MPI_INIT: MPI_INIT: 启动启动 MPIMPI 环境环境MPI_COMM_SIZE: MPI_COMM_SIZE: 确定进程数确定进程数MPI_COMM_RANK: MPI_COMM_RANK: 确定自己的进程标识确定自己的进程标识符符MPI_SEND: MPI_SEND: 发送一条消息发送一条消息MPI_RECV: MPI_RECV: 接收一条消息接收一条消息MPI_FINALIZE: MPI_FINALIZE: 结束结束 MPIMPI 环境环境

Page 13: MPI 分布内存并行 程序开发

1313

程序程序 11 、 简单例子、 简单例子

program maininclude 'mpif.h'

character * (MPI_MAX_PROCESSOR_NAME) processor_nameinteger myid,numprocs,namelen,rc,ierr

call MPI_INIT(ierr)call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)call

MPI_GET_PROCESSOR_NAME(processor_name,namelen,ierr)

write (*,10) myid,numprocs,processor_name10 FORMAT('Hello World! Process',I2,' of ',I1,' on ',20A)

call MPI_FINALIZE(rc) end

Page 14: MPI 分布内存并行 程序开发

1414

程序程序 11 、 简单例子、 简单例子#include “mpi.h”main(int argc, char **argv){ int numprocs,myrank,i,j,k; MPI_Status status; char msg[20];

MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); if(myrank == 0){ strcpy(msg,”Hello World”); MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,1,99,MPI_COMM_WORLD); }else if(myrank ==1 ) { MPI_Recv(msg,20,MPI_CHAR,0,99,MPI_COMM_WORLD,&status); printf(“Receive message = %s\n”,msg); } MPI_Finalize();}

Page 15: MPI 分布内存并行 程序开发

1515

MPIMPI 程序的一般结构程序的一般结构包含 MPI 头文件

初始化 MPI 环境

消息交换处理及计算等

退出 MPI 环境

Page 16: MPI 分布内存并行 程序开发

1616

头文件头文件

MPIMPI 程序要求:所有包含程序要求:所有包含 MPIMPI 调用的程序调用的程序文件头应加入:文件头应加入:

C 包含文件 Fortran 包含文件#include “mpi.h” Include ‘mpif.h’

Page 17: MPI 分布内存并行 程序开发

1717

编译,执行:编译,执行:

mpicc -o hello hello.c:mpicc -o hello hello.c: 生成执行文件生成执行文件 hellhelloo

mpirun -np n hello: mpirun -np n hello: 加载加载 nn 个进程运行,个进程运行,00 号进程发送,号进程发送, 11 号进程接受并打印字号进程接受并打印字符串符串

Page 18: MPI 分布内存并行 程序开发

1818

通信因子和组通信因子和组

MPIMPI 通过指定通信因子和组来对进程进行一种通过指定通信因子和组来对进程进行一种逻辑上的划分,通讯因子定义了进程组内或组逻辑上的划分,通讯因子定义了进程组内或组间通讯的上下文(具体就是指明通讯链路的数间通讯的上下文(具体就是指明通讯链路的数据结构指针)。据结构指针)。

MPI_COMM_WORLDMPI_COMM_WORLD 通信因子是在通信因子是在 MPIMPI 环境环境初始化过程中创建初始化过程中创建

Page 19: MPI 分布内存并行 程序开发

1919

进程号进程号 ((rank)rank)

在一个通信因子中,每个进程都有一个唯一的在一个通信因子中,每个进程都有一个唯一的整数标识符,称作“进程整数标识符,称作“进程 ID”ID” ,,进程号是从进程号是从 00开始的连续整数。开始的连续整数。

if (rank ==0) {第 0 进程运行的程序段

} else if(rank == 1) {第 1 进程运行的程序段

}

Page 20: MPI 分布内存并行 程序开发

2020

MPIMPI 消息消息

MPIMPI 消息包括信封和数据两个部分,信封指消息包括信封和数据两个部分,信封指出了发送或接收消息的对象及相关信息,而出了发送或接收消息的对象及相关信息,而数据是本消息将要传递的内容。数据是本消息将要传递的内容。

数据:数据: << 起始地址,数据个数,数据类型起始地址,数据个数,数据类型 >> 信封:信封: << 源源 // 目,标识,通信域目,标识,通信域 >>

Page 21: MPI 分布内存并行 程序开发

2121

MPIMPI 的基本函数的基本函数

MPI_InitMPI_Init MPI_Comm_sizeMPI_Comm_size MPI_Comm_rankMPI_Comm_rank MPI_SendMPI_Send MPI_RecvMPI_Recv MPI_FinalizeMPI_Finalize

Page 22: MPI 分布内存并行 程序开发

2222

MPI_Init()MPI_Init()

MPIMPI 的初始化例行函数,用于初始化的初始化例行函数,用于初始化 MPIMPI运行环境。运行环境。

必须调用;首先调用;调用一次。必须调用;首先调用;调用一次。 MPI_Init (*argc,*argv) MPI_Init (*argc,*argv) 。。每个进程都有一每个进程都有一

个参数表。个参数表。

Page 23: MPI 分布内存并行 程序开发

2323

MPI_Comm_size()MPI_Comm_size()

该函数返回与该组通信因子相关的进程数,显该函数返回与该组通信因子相关的进程数,显然这里的通讯因子必须是组内通讯因子。然这里的通讯因子必须是组内通讯因子。

MPI_Comm_size (comm,*size) MPI_Comm_size (comm,*size)

Page 24: MPI 分布内存并行 程序开发

2424

MPI_Comm_rank()MPI_Comm_rank()

该函数返回该进程在指定通信因子中的进程号该函数返回该进程在指定通信因子中的进程号(( 0 ~ 0 ~ 进程数进程数 -1-1 ),一个进程在不同通信因子),一个进程在不同通信因子中的进程号可能不同:中的进程号可能不同:

MPI_Comm_rank (comm,*rank) MPI_Comm_rank (comm,*rank)

Page 25: MPI 分布内存并行 程序开发

2525

MPI_Send()MPI_Send()

该函数将发送缓冲区中的该函数将发送缓冲区中的 countcount 个个datatypedatatype 数据类型的数据发送到目的进程数据类型的数据发送到目的进程

MPI_Send(buf,count,datatype,dest,tag,coMPI_Send(buf,count,datatype,dest,tag,comm)mm)

Page 26: MPI 分布内存并行 程序开发

2626

MPI_Recv()MPI_Recv()

该函数从指定的进程该函数从指定的进程 sourcesource 接收消息,接收消息,并且该消息的数据类型和消息标识和本接并且该消息的数据类型和消息标识和本接收进程指定的数据类型和消息标识相一致,收进程指定的数据类型和消息标识相一致,收到的消息所包含的数据元素的个数最多收到的消息所包含的数据元素的个数最多不能超过不能超过 count.count.

MPI_Recv(buf,count,datatype,source,coMPI_Recv(buf,count,datatype,source,comm,status)mm,status)

Page 27: MPI 分布内存并行 程序开发

2727

MPI_Finalize()MPI_Finalize()

结束结束 MPIMPI 执行环境。该函数执行环境。该函数一旦被应用程序调一旦被应用程序调用时,就不能调用用时,就不能调用 MPIMPI 的其它例行函数(包括的其它例行函数(包括MPI_InitMPI_Init ) ,) , 用 户 必 须 保 证 在 进 程 调 用用 户 必 须 保 证 在 进 程 调 用MPI_FinalizeMPI_Finalize 之前把与完成进程有关的所有通之前把与完成进程有关的所有通信结束。信结束。

MPI_Finalize ()MPI_Finalize ()

Page 28: MPI 分布内存并行 程序开发

2828

参数说明参数说明 缓冲区(缓冲区( bufferbuffer )) 数据个数(数据个数( countcount )) 数据类型(数据类型( typetype )) 目的地 (目的地 ( destdest )) 源 (源 ( sourcesource )) 标识符(标识符( tagtag )) 通信因子(通信因子( commcomm )) 状态(状态( statusstatus ))

Page 29: MPI 分布内存并行 程序开发

2929

缓冲区(缓冲区( bufferbuffer ))

指应用程序定义地用于发送或接收数据的消息指应用程序定义地用于发送或接收数据的消息缓冲区。缓冲区。

Page 30: MPI 分布内存并行 程序开发

3030

数据个数(数据个数( countcount ))

指发送或接收指定数据类型的个数。指发送或接收指定数据类型的个数。 数据类型的长度 数据类型的长度 * * 数据个数的值为用户实际传数据个数的值为用户实际传

递的消息长度。递的消息长度。

Page 31: MPI 分布内存并行 程序开发

3131

数据类型(数据类型( typetype ))

MPIMPI 定义了一些缺省的数据类型,用户也可以定义了一些缺省的数据类型,用户也可以根据需要建立自己的数据类型根据需要建立自己的数据类型

Page 32: MPI 分布内存并行 程序开发

3232

MPI C语言数据类型 MPI Fortran语言数据类型MPI _CHAR si gned char MPI _CHARACTER character(1)MPI _SHORT si gned short i ntMPI _I NT si gned i nt MPI _I NTEGER i ntegerMPI _LONG si gned l ong i ntMPI _UNSI GNED_CHAR unsi gned charMPI _UNSI GNED_SHORT unsi gned short i ntMPI _UNSI GNED unsi gned i ntMPI _UNSI GNED_LONG unsi gned l ong i ntMPI _FLOAT fl oat MPI _REAL realMPI _DOUBLE doubl e MPI _DOUBLE_PRECI SI ON doubl e preci si onMPI _LONG_DOUBLE l ong doubl e

MPI _COMPLEX compl exMPI _LOGI CAL l ogi cal

MPI _BYTE 8 bi nary di gi ts MPI _BYTE 8 bi nary di gi ts

MPI _PACKEDdata packed orunpacked wi thMPI _Pack()/MPI _Unpack

MPI _PACKEDdata packed orunpacked wi thMPI _Pack()/MPI _Unpack

续上页续上页

Page 33: MPI 分布内存并行 程序开发

3333

目的地 (目的地 ( destdest ))

发送进程指定的接收该消息的目的进程,也就发送进程指定的接收该消息的目的进程,也就是接收进程的进程号(注意组间通讯的情况)。是接收进程的进程号(注意组间通讯的情况)。

Page 34: MPI 分布内存并行 程序开发

3434

源 (源 ( sourcesource ))

接收进程指定的发送该消息的源进程,也就是接收进程指定的发送该消息的源进程,也就是发 送 进 程 的 进 程 号 。 如 果 该 值 为发 送 进 程 的 进 程 号 。 如 果 该 值 为MPI_ANY_SOURCEMPI_ANY_SOURCE 表示接收任意源进程发来表示接收任意源进程发来的消息。的消息。

Page 35: MPI 分布内存并行 程序开发

3535

标识符(标识符( tagtag ))

由程序员指定地为标识一个消息的唯一非负整由程序员指定地为标识一个消息的唯一非负整数值(数值( 0-327670-32767 ),发送操作和接收操作的标),发送操作和接收操作的标识符一定要匹配,但对于接收操作来说,如果识符一定要匹配,但对于接收操作来说,如果tagtag 指定为指定为 MPI_ANY_TAGMPI_ANY_TAG 则可与任何发送操则可与任何发送操作的作的 tagtag 相匹配。相匹配。

Page 36: MPI 分布内存并行 程序开发

3636

通信因子(通信因子( commcomm ))

包含源与目的进程的一组上下文相关的进程集包含源与目的进程的一组上下文相关的进程集合,除非用户自己定义(创建)了新的通信因合,除非用户自己定义(创建)了新的通信因子,否则一般使用系统预先定义的全局通信因子,否则一般使用系统预先定义的全局通信因子子 MPI_COMM_WORLDMPI_COMM_WORLD 。。

Page 37: MPI 分布内存并行 程序开发

3737

状态(状态( statusstatus )) 对 于 接 收操作 , 包 含 了 接 收 消 息 的 源 进 程对 于 接 收操作 , 包 含 了 接 收 消 息 的 源 进 程

(( sourcesource )) 和 消 息 的 标 识 符 (和 消 息 的 标 识 符 ( tagtag ) 。) 。 在在FORTRANFORTRAN 程 序 中 , 这 个 参 数 是 包 含程 序 中 , 这 个 参 数 是 包 含MPI_STATUS_SIZEMPI_STATUS_SIZE 个 整 数 的 数个 整 数 的 数组,组, statusstatus (( MPI_SOURCEMPI_SOURCE )、)、 statusstatus (( MPI_MPI_TAGTAG ))和和 statusstatus (( MPI_ERRORMPI_ERROR ))分别表示数据分别表示数据的进程标识、发送数据使用的进程标识、发送数据使用 tagtag 标识和接收操作返标识和接收操作返回的错误代码。回的错误代码。

相当于一种在接受方对消息的监测机制,并且以其相当于一种在接受方对消息的监测机制,并且以其为依据对消息作出不同的处理(当用通配符接受消为依据对消息作出不同的处理(当用通配符接受消息时)。息时)。

Page 38: MPI 分布内存并行 程序开发

3838

程序程序 11 、简单例子、简单例子#include “mpi.h”main(int argc, char **argv){ int numprocs,myrank,i,j,k; MPI_Status status; char msg[20];

MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); if(myrank == 0){ strcpy(msg,”Hello World”); MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,1,99,MPI_COMM_WORLD); }else if(myrank ==1 ) { MPI_Recv(msg,20,MPI_CHAR,0,99,MPI_COMM_WORLD,&status); printf(“Receive message = %s\n”,msg); } MPI_Finalize();}

Page 39: MPI 分布内存并行 程序开发

3939

程序程序 22 、 、 ππ 的计算的计算 ##include “mpi.h”include “mpi.h” #include <stdio.h>#include <stdio.h> #include <math.h>#include <math.h> double f(double x);/*double f(double x);/* 定义函数定义函数 f(x) */f(x) */ {{ return(4.0/(1.0+x*x));return(4.0/(1.0+x*x)); } } int main (int argc,char * argv[])int main (int argc,char * argv[]) {{ int done =0,n,myid,numprocs,i;int done =0,n,myid,numprocs,i; double PI25DT=3.141592653589793238462643;double PI25DT=3.141592653589793238462643; double mypi,pi,h,sum,x;double mypi,pi,h,sum,x; double startwtime=0.0,endwtime;double startwtime=0.0,endwtime; int namelen;int namelen; char processor_name[MPI_MAXPROCESSOR_NAME]; char processor_name[MPI_MAXPROCESSOR_NAME]; MPI_Status status; MPI_Status status;

0 1

-1

-1

1

Page 40: MPI 分布内存并行 程序开发

4040

MPI_Init(&argc,&argv);MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs);MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid);MPI_Comm_rank(MPI_COMM_WORLD,&myid); MPI_Get_processor_name(processor_name,&namelen);MPI_Get_processor_name(processor_name,&namelen); fprint(stdout,”Process %d of %d on % s\n”,myid,numprocs,fprint(stdout,”Process %d of %d on % s\n”,myid,numprocs, processor_name);processor_name); n=0;n=0; if (myid==0)if (myid==0) {{ printf(“Please give N=”);printf(“Please give N=”); scanf(&n);scanf(&n); startwtime=MPI_Wtime();startwtime=MPI_Wtime(); for (j=1;j<numprocs;j++)for (j=1;j<numprocs;j++) {{ MPI_Send(&n,1,MPI_INT,j,99,MPI_COMM_WORLD);MPI_Send(&n,1,MPI_INT,j,99,MPI_COMM_WORLD); }} }}

Page 41: MPI 分布内存并行 程序开发

4141

elseelse

{ MPI_Recv(&n,1,MPI_INT,MPI_ANY_SOURCE,99,MPI_COMM_{ MPI_Recv(&n,1,MPI_INT,MPI_ANY_SOURCE,99,MPI_COMM_WORLD,&status);WORLD,&status);

}}

h=1.0/(double) n;h=1.0/(double) n;

sum=0.0;sum=0.0;

for(i=myid+1;i<=n;i+=numprocs)for(i=myid+1;i<=n;i+=numprocs)

/* /* 每一个进程计算一部分矩形的面积,若进程总数每一个进程计算一部分矩形的面积,若进程总数 numprocsnumprocs 为为 44 ,, 将 将 0-10-1 区间划分为区间划分为 100100 个矩形,则各个进程分别计算矩形块个矩形,则各个进程分别计算矩形块 00 进程 进程 11 ,, 55 ,, 99 ,, 1313 ,……,,……, 9797

11 进程 进程 22 ,, 66 ,, 1010 ,, 1414 ,……,,……, 9898

22 进程 进程 33 ,, 77 ,, 1111 ,, 1515 ,……,,……, 9999

33 进程 进程 44 ,, 88 ,, 1212 ,, 1616 ,……,,……, 100 */100 */

Page 42: MPI 分布内存并行 程序开发

4242

{{ x=h*((double)i-0.5);x=h*((double)i-0.5); sum+=f(x);sum+=f(x); }} mypi=h*sum; /*mypi=h*sum; /* 各进程并行计算得到的部分和各进程并行计算得到的部分和 */*/

/*/* 将部分和累加得到所有矩形的面积,该面积和即为近似将部分和累加得到所有矩形的面积,该面积和即为近似 PIPI值值 */*/ if (myid != 0)if (myid != 0)

MPI_Send(&mypi,1,MPI_DOUBLE,0,myid,MPI_COMM_WORLD)MPI_Send(&mypi,1,MPI_DOUBLE,0,myid,MPI_COMM_WORLD);;

elseelse { {

pi=0.0;pi=0.0;pi=pi+mypi;pi=pi+mypi;

Page 43: MPI 分布内存并行 程序开发

4343

for (j=1;j<numprocs;j++)for (j=1;j<numprocs;j++) { { MPI_Recv(&mypi,1,MPI_DOUBLE,MPI_ANY_SOURCE,MPI_Recv(&mypi,1,MPI_DOUBLE,MPI_ANY_SOURCE, MPI_ANY_TAG,MPI_COMM_WORLD,&status);MPI_ANY_TAG,MPI_COMM_WORLD,&status);

pi=pi+mypi;pi=pi+mypi; } } printf(“pi is approximately %.16f,Error is %.16f\n”,printf(“pi is approximately %.16f,Error is %.16f\n”, pi,fabs(pi-PI25DT));pi,fabs(pi-PI25DT)); endwtime=MPI_Wtime();endwtime=MPI_Wtime(); printf(“wall clock time=% f\n”,endwtime-startwtime);printf(“wall clock time=% f\n”,endwtime-startwtime); fflush(stdout);fflush(stdout); }} MPI_Finalize();MPI_Finalize(); } }

Page 44: MPI 分布内存并行 程序开发

4444

谢谢!谢谢!