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程序
两个进程之间进行数据交换的时候,一定要将他们的发送和接收的顺序进行匹配,也就是一个进程的发送在前,接收在后,相应的,另一个进程的接收在前,发送在后。
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来代替相应的阻塞操作
数据类型不匹配
接收缓冲区溢出
正确使用地址
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)