高性能计算机MPI程序设计方案分享
2022-10-13 09:38:17 0 举报
AI智能生成
高性能计算机MPI程序设计方案分享
作者其他创作
大纲/内容
1 并行计算机
并行计算机的分类
指令与程序
程序和数据
SPMD
MPMD
指令和数据
MIMD
SIMD
存储方式
共享内存
分布式内存
分布式共享内存
物理问题在并行机上的求解
2 并行编程模型与并行语言
并行编程模型
数据并行
消息传递
并行语言
全新的语言
扩展原来的语法
并行库
3 并行算法
分类
对象
数值型
非数值型
进程间的依赖
同步并行算法
异步并行算法
纯并行算法
并行任务的大小
粗粒度并行算法
细粒度并行算法
介于二者之间
设计
SIMD
适合于同步并行算法,加大计算时间相对于通信时间的比重,减少通信的次数,甚至以计算换通信
MPMD
适合于异步并行算法
4 MPI简介
MPI
一个库而不是一种语言
一种标准或规范,而不是实现
一种消息传递模型、标准
目的
提供应用程序的编程接口
提高通信效率、措施,避免多次重复拷贝,允许计算和通信的重叠
异构环境
C和Fortran 77
可靠的通信接口
允许扩展
。。。
实现
MPICH
Chimp
Lam
OpenMPI
5 MPI程序
C与MPI绑定
头文件 #include "mpi.h"
程序开始 MPI_Init(&argc, &argv);
程序结束 MPI_Finalize();
程序体
进程的标志号 MPI_Comm_rank
进程的个数 MPI_Comm_size
机器的名称 MPI_Get_processor_name
惯例
都是以MPI_开始,c中首字母大小,其他的小写
6 六个接口构成的MPI的子集
6个子集
6个常用的接口
初始化 MPI_Init(int *argc,char ***argv)
结束 MPI_Finalize(void)
当前进程标识 int MPI_Comm_rank(MPI_Comm comm,int *rank)
通信域包含的进程数 int MPI_Comm_size(MPI_Comm comm, int *size)
消息发送 int MPI_Send(void *buf,int count,MPI_Datatype,int dest,int tag,MPI_Comm comm)
消息接收 int MPI_Recv(void *buf,int count,MPI_Datatype datatype,int source ,int tag,MPI_Comm comm,MPI_Status *status)
MPI调用参数说明
IN 输入
OUT 输出
INOUT 输入输出
预定义类型
基本类型都是将类型大写,并在前面加上MPI_
MPI_BYTE和MPI_PACKED在c中没有对应的类型
数据类型匹配和数据转换
MPI类型匹配规则
消息传递的三个过程
消息装配
缓冲区内变量类型=发送类型
消息传递
发送类型=接收类型
消息拆卸
接收缓冲区类型=接收类型
有类型数据的通信
发送方和接收方一致
无类型数据的通信
发送方和接收方均以MPI_BYTE作为类型
打包数据通信
发送方和接收方均使用MPI_PACKED
数据转换
数据类型的转换
基本没有
数据表示的转换
改变一个值的二进制表示
MPI消息
MPI消息的组成
数据
数据:<起始地址,数据个数,数据类型>
信封
信封:<源/目,标识,通信域>
MPI_Send(void *buf,int count,MPI_Datatype,int dest,int tag,MPI_Comm comm)
MPI_Recv(void *buf,int count,MPI_Datatype datatype,int source ,int tag,MPI_Comm comm,MPI_Status *status)
任意源和任意标识
接受者可以通过MPI_ANY_SOURCE来接收任何类型的消息
MPI通信域
进程组
所有参加通信的集合,N个就是进程号从0~N-1
通信上下文
提供一个相对对立的通信区域
7 简单的MPI程序示例
MPI的计时功能
MPI_Wtime()
MPI_Wtick()
获取机器的名字和MPI版本号
MPI_Get_version(int * version, int * subversion)
MPI_Get_processor_name(char *name,int *resultlen)
是否初始化及错误退出
MPI_Initalizer(int * flag)
MPI_Abort(MPI_Comm comm,int eoorcode)
数据接力传输
任意进程间相互问候
任意进程都可以向其他的进程问好,任意连个进程之间都可以进行数据交换
任意源和任意标识的使用
编写安全的MPI程序
两个进程之间进行数据交换的时候,一定要将他们的发送和接收的顺序进行匹配,也就是一个进程的发送在前,接收在后,相应的,另一个进程的接收在前,发送在后。
8 MPI并行程序的两种模式
对等模式
Jacobi迭代
牛顿迭代
Jacobi迭代
MPI实现Jacobi迭代
通过划分数据块的方法
使用捆绑发送接收实现Jacobi迭代
MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest,int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source,int recvtag, MPI_Comm comm, MPI_Status *status)
捆绑发送接收是不对称的
PI_Sendrecv_replace(void *buf, int count, MPI_Datatype datatype, int dest, int sendtag,int source, int recvtag, MPI_Comm comm, MPI_Status *status)
虚拟进程实现Jacobi迭代
MPI_PROC_NULL
简化代码
将虚拟进程充当进程通信的源或者目
主从模式
矩阵向量相乘
主从进程之间的打印数据
9 不同通信模式MPI并行程序设计
不同通信模式的区分
是否需要对发送的数据进行缓存
是否只有当接收调用执行后才可以执行发送操作
什么时候发送调用可以正确返回
发送调用正确返回是否意味着发送完毕
即发送缓冲区是否可以被覆盖
发送数据是否已达到接收缓冲区
四种通信模式
标准通信模式
是否对发送的数据进行缓存由MPI自身决定,不由程序员决定
如果MPI决定缓存将要发出的数据,发送操作不管接收操作是否执行,都可以继续执行
发送操作可以正确返回,而不要求接收操作收到发送的数据
缓存数据会延长数据通信的时间,而且缓冲区不一定能够得到
缓存通信模式
用程序员自己控制
MPI_Bsend(void* buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm)
缓存通信不管接收操作是否启动,发送操作都是可以执行的
发送消息之前必须要有缓冲区可以使用
必须要等到缓冲区中的消息发送之后,才可以释放缓冲区
MPI_Buffer_attach(void* buffer, int size)
MPI_Buffer_detach(void** buffer, int* size)
同步通信模式
其开始不依赖于接收进程相应的接收操作是否已经进行,但是必须等到相应的接收进程开始后才可以正确返回
同步发送返回后,意味着发送缓冲区中的数据已经全部被系统缓冲区缓存,并且已经开始发送。此时同步发送返回后,发送缓冲区可以被释放或者重新利用
就绪通信模式
只有当接收进程的接收操作已经启动时,才可以在发送进程启动发送操作
接收操作必须先于发送操作
对于非阻塞发送操作的正确返回,并不意味着发送已经完成,但对于阻塞发送的正确返回,则发送缓冲区可以重读使用
10 安装MPI
11 安装常见错误
程序设计中的错误
缺少ierr参数
对status的错误说明
对于字符串的说明
以MPI_声明变量
argc,argv的参数使用
不要在MPI_Init前和MPI_Finalize后面编写程序
不要用MPI_Recv和MPI_Bcast相匹配
不能假设MPI支持多线程
MPI_Send和MPI_Recv的不合理次序
将发送和接收重叠起来吗,即当一方在发送时另一方处于接收状态,这样可以避免因相互等待而造成死锁
对于成对的交互发送和接收,鼓励使用MPI_Sendrecv语句,因为该语句本身提供了优化的可能,可以既提高效率,又避免编写单独的MPI_Send和MPI_Recv语句可能造成的死锁问题。
用MPI_Buffer_attach来显式分配用户自己的存储空间。
鼓励使用非阻塞操作MPI_Isend和MPI_Irecv来代替相应的阻塞操作
数据类型不匹配
接收缓冲区溢出
正确使用地址
12 非阻塞通信MPI程序设计
13 组通信MPI程序设计
组通信概述
组通信的消息通信功能
一对多
多对一
多对多
组通信的同步功能
协调各个进程之间的步伐和进度
组通信的计算功能
通信的功能
对消息的处理
将处理结果存放在指定的接收缓冲区
广播
一对多的通信
MPI_Bcast(void* buffer,int count,MPI_Datatype datatype,int root, MPI_Comm comm)
收集
多对一的通信
MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype,void* recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)
散发
一对多的通信
MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype,void* recvbuf, int recvcount, MPI_Datatype recvtype,int root, MPI_Comm comm)
组收集
将每一个进程作为一个root进程,执行一次MPI_GATHER,所有进程都将接收到结果
MPI_Allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype,void* recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)
全互换
MPI_ALLTOALL组内所有的进程完全的交换消息,每个进程都会从其他的进程发送消息和接收消息
MPI_ALLGATHER每个进程散发一个相同的消息给所有的进程,MPI_ALLTOALL散发给每个进程的消息是不相同的,发送缓冲区是一个数组
MPI_Alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype,void* recvbuf, int recvcount, MPI_Datatype recvtype,MPI_Comm comm)
同步
MPI_Barrier(MPI_Comm comm)
归约
MPI_REDUCE将组内每个进程输入缓冲区中的数据按给定的操作op进行运算,并将其结果返回到序列号为root的进程的输出缓冲区中
MPI_Reduce(void* sendbuf, void* recvbuf, int count, PI_Datatype datatype,MPI_Op op, int root, MPI_Comm comm)
MPI预定义的归约操作
求π值
组归约
MPI_ALLREDUCE相当于组中每个进程作为root分别进行了一次规约操作。即规约的结果不只是某一个进程拥有,而是所有的进程都拥有。
MPI_Allreduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype,MPI_Op op, MPI_Comm comm)
归约并散发
MPI_REDUCE_SCATTER将归约的结果分散到组内的所有进程中,而不是仅仅归约到root进程。
MPI_Reduce_scatter(void* sendbuf, void* recvbuf, int *recvcounts,MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
扫描
每一个进程都对排在它前面的进程进行归约操作
MPI_Scan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
不同类型归约操作的简单对比
归约
组归约
归约并发散
不正确的组通信方式
用户自定义归约操作
MPI_Op_create(MPI_User_function *function,int commute,MPI_Op *op)
0 条评论
下一页