MPI编程及性能优化
第1节 MPI简介
1.1 MPI及其历史
1.2 典型MPI实现简介
支持多程序多数据(Multiple Program Multiple Data,MPMD)编程和异构集群系统;
支持C/C++、Fortran 77 和Fortran 90的绑定;对Fortran的支持提供了头文件mpif.h和模块两种方式;
支持环境非常广泛,包括多核、SMP、集群和大规模并行计算系统;
除此之外,MPICH软件包中还集成了并行程序设计环境组件,包括并行性能可视化分析工具和性能测试工具等。
Intel MPI是由Intel公司推出的符合MPI-2标准的MPI实现。其最新版本是3.0版,突出的特色在于提供了灵活的多架构支持。
图7.1 Intel MPI库及其基于 DAPL 的互联结构
从图7.1可以看出,Intel MPI透明地支持TCP/IP、共享内存,并基于DAPL有效支持多种高性能互联系统, Intel MPI提供更好的线程安全机制,多线程的MPI程序并不限制MPI的使用。
1.3 MPI程序特点
MPI程序是基于消息传递的并行程序。消息传递指的是并行执行的各个进程具有自己独立的堆栈和代码段,作为互不相关的多个程序独立执行,进程之间的信息交互完全通过显式地调用通信函数来完成。
SPMD是MPI程序中最常用的并行模型。图7.2为SPMD执行模型的示意图,其中表示了一个典型的SPMD程序,同样的程序prog_a运行在不同的处理核上,处理了不同的数据集。
图7.5则给出了三种典型MPMD程序的执行模型。
(a)是一个管理者(Master)/工人(Worker)类型的MPMD程序
(b)为另外一种类型的MPMD程序:联合数据分析程序。在大部分的时间内,不同的程序各自独立的完成自己的任务,并在特定的时候交换数据。
(c)是流式的MPMD程序,程序运行由prog_a、prog_b和prog_c组成,这三个程序的执行过程就好像工厂里的流水线一样。
图 7.5 MPMD执行模型
通过学习本小节介绍的MPI程序的特点,以及SPMD和MPMD的多种执行模型,读者就可以在以后的开发过程中灵活地设计不同的MPI并行程序。
PI-2提出的高级功能将在第7.6节中将做简要说明。
第2节 MPI编程基础
2.1 简单的MPI程序示例
首先,我们来看一个简单的MPI程序实例。如同我们学习各种语言的第一个程序一样,对于MPI的第一个程序同样是"Hello Word"。
int main( int argc, char *argv[] ) {
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf( "Hello world from process %d of %d\n", rank, size );
运行这个例子可以在可执行文件的目录中执行mpiexec –np 4 ./hellow。运行结果如下:
Hello world from process 0 of 4
Hello world from process 1 of 4
Hello world from process 2 of 4
Hello world from process 3 of 4
这个程序在MPI程序运行的每个进程中分别打印各自的MPI进程号(0~3)和总进程数(4)。
值得注意的是,由于四个进程是并行执行,所以即使输出的顺序有变化也是正常的,程序中并没有限制哪个进程在前,哪个进程在后。
2.2 MPI程序的四个基本函数
MPI_Init用来初始化MPI执行环境,建立多个MPI进程之间的联系,为后续通信做准备。而MPI_Finalize则是结束MPI执行环境。
如同OpenMP定义并行区一样,这两个函数就是用来定义MPI程序的并行区的。也就是说,除了检测是否初始化的函数之外,不应该在这两个函数定义的区域之外调用其他MPI函数。
整型指针,返回进程在相应进程组中的进程号。进程号从0开始编号。
2.3 MPI的点对点通信
点对点通信是MPI编程的基础。本节我们将重点介绍其中两个最重要的MPI函数MPI_Send和MPI_Recv。
int MPI_SEND(buf, count, datatype, dest, tag, comm); |
datatype,发送数据的数据类型,这个参数将在后续节中详细介绍。
这个函数的含义是向通信域comm中的dest进程发送数据。消息数据存放在buf中,类型是datatype,个数是count个。这个消息的标志是tag,用以和本进程向同一目的进程发送的其它消息区别开来。
int MPI_RECV(buf,count,datatype,source,tag,comm,status); |
n status,MPI_Status结构指针,返回状态信息。
/* The order of these elements must match that in mpif.h */ typedef struct MPI_Status { int count; int cancelled; int MPI_SOURCE; int MPI_TAG; int MPI_ERROR; } MPI_Status; |
int MPI_Get_count( MPI_Status *status, MPI_Datatype datatype, int *count); |
2.4 消息管理7要素
MPI最重要的功能莫过于消息传递。正如我们先前看到一样,MPI_Send和MPI_Recv负责在两个进程间发送和接收消息。总结起来,点对点消息通信的参数主要是由以下7个参数组成:
(4) 目标进程或者源进程destination/source;
在消息缓冲的三个变量中,最值得注意的是datatype,消息数据类型。
如前所述,我们需要发送和接收连续的数据,MPI提供了预定义的数据类型供程序员使用。
MPI预定义数据类型 |
相应的C数据类型 |
MPI_CHAR |
signed char |
MPI_SHORT |
signed short int |
MPI_INT |
signed int |
MPI_LONG |
signed long int |
MPI_UNSIGNED_CHAR |
unsigned char |
MPI_UNSIGNED_SHORT |
unsigned short int |
MPI_UNSIGNED |
unsigned int |
MPI_UNSIGNED_LONG |
unsigned long int |
MPI_FLOAT |
float |
MPI_DOUBLE |
double |
MPI_LONG_DOUBLE |
long double |
MPI_BYTE |
无对应类型 |
MPI_PACKED |
无对应类型 |
除了这些基本数据类型之外,MPI还允许通过导出数据类型,将不连续的,甚至是不同类型的数据元素组合在一起形成新的数据类型。我们称这种由用户定义的数据类型为导出数据类型。
无类型数据的通信,发送方和接收方均以MPI_BYTE作为数据类型;
一个通信域(comm)包含一个进程组(process group)及其上下文(context)。进程组是进程的有限有序集。通信域限定了消息传递的进程范围。
(2) 通信域拷贝int MPI_Comm_dup(comm, newcom):对comm进行复制得到新的通信域newcomm。
(4) 通信域销毁int MPI_Comm_free(comm):释放给定通信域。
2.5 统计时间
2.6 错误管理
MPI在错误管理方面提供了丰富的接口函数,这里我们介绍其中最简单的部分接口。
int MPI_Abort(MPI_Comm comm, int errorcode) |
它使comm通信域的所有进程退出,返回errorcode给调用的环境。通信域comm中的任一进程调用此函数都能够使该通信域内所有的进程结束运行。
第3节 MPI群集通信
除了前面介绍的点到点通信之外,MPI还提供了群集通信。所谓群集通信,包含了一对多,多对一和多对多的进程通信模式。它的最大的特点就是多个进程参与通信,下面我们将要介绍在MPI中常用的几个群集通信函数。
3.1 同步
本函数接口是:int MPI_Barrier(MPI_Comm comm)。
3.2 广播
广播顾名思义,就是一对多的传送消息。它的作用是从一个root进程向组内所有其他的进程发送一条消息。它的接口形式是:
int MPI_Bcast( void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm )
3.3 聚集
聚集函数MPI_Gather是一个多对一的通信函数。其接口为:
int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
void *recvbuf, int recvcnt, MPI_Datatype recvtype,
3.4 播撒
int MPI_Scatter(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root,
播撒函数MPI_Scatter是一对多的传递消息。但是它和广播不同,root进程向各个进程传递的消息是可以不同的。Scatter实际上执行的是与Gather相反的操作。
3.5扩展的聚集和播撒操作
int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
3.6全局交换
int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
3.7规约与扫描
MPI提供了两种类型的聚合操作:归约(reduction)和扫描(scan)。
int MPI_Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
MPI_Op op, int root, MPI_Comm comm)
操作 |
允许的数据类型 |
MPI_MAX,MPI_MIN |
C整数,Fortran整数,浮点数 |
MPI_SUM,MPI_PROD |
C整数,Fortran整数,浮点数,复数 |
MPI_LAND,MPI_LOR,MPI_XLOR |
C整数,逻辑型 |
MPI_BAND,MPI_BOR,MPI_BXOR |
C整数,Fortran整数,字节型 |
在MPI中,针对规约操作,所有的MPI预定义的操作都是可结合的,也是可交换的。同时,用户可以指定自定义的函数操作,这些操作是也要可结合的,但可以不是可交换的。
2.扫描
int MPI_Scan(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
MPI_Op op, MPI_Comm comm)
MPI_Scan常用于对分布于组中的数据作前置归约操作。此操作将序列号为0,···,i(包括i)的进程发送缓冲区的归约结果存入序列号为i 的进程接收消息缓冲区中。这种操作支持的数据类型、操作以及对发送及接收缓冲区的限制和规约相同。与规约相比,扫描Scan操作省去了Root域,因为扫描是将部分值组合成n个最终值,并存放在n个进程的recvbuf中。具体的扫描操作由Op域定义。
MPI的归约和扫描操作允许每个进程贡献向量值,而不只是标量值。向量的长度由Count定义。MPI也支持用户自定义的归约操作。
第4节 MPI性能分析与优化举例
4.1 选取计算粒度
当通信的成为并行程序性能瓶颈的时候,一般来说选取较高的计算粒度可以降低进程间的通信开销。例如,用7个进程完成A、B、C 3个不相关的任务,如果B的计算量为A的2倍,而C的计算量为A的4倍。
|
4.2聚合消息
一种减少通信次数的方法就是将小的消息聚合起来一次发送,这种优化称为消息聚合。如果零碎的消息很多,则通过消息聚合可以得到很大的性能提高。
4.3解决负载均衡问题
from: http://jpck.zju.edu.cn/eln/200805131515180671/page.jsp?cosid=1423&JSPFILE=page&LISTFILE=list&CHAPFILE=listchapter&PATH=200805131515180671&ROOTID=6380&NODEID=6403&DOCID=8717
MPI编程及性能优化相关推荐
- 编程之性能优化知多少
来源:『圣杰』 cnblogs.com/sheng-jie/p/7109385.html 一.引言 性能优化是一个老生常谈的问题了,典型的性能问题如页面响应慢.接口超时,服务器负载高.并发数低,数据库 ...
- C语言嵌入系统编程修炼-性能优化
2019独角兽企业重金招聘Python工程师标准>>> 本文来自:智趣网-C/C++语言编程技术交流论坛 http://www.bczh.net 使用宏定义 在 C语言中,宏是产生内 ...
- Linux C++性能优化秘籍:从编译器到代码,探究高性能C++程序的实现之道
Linux C++性能优化秘籍:从编译器到代码,揭秘高性能C++程序的实现之道 引言 性能优化的重要性 Linux环境下C++程序的特点 高性能C++编程的核心要点 编译器优化 GCC与Clang编译 ...
- Java中性能优化的35种方法汇总
原文地址:http://www.jb51.net/article/102831.htm 前言 对程序员们来说,代码优化是一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于 ...
- (十二)运行环境(加载、性能优化、安全)【这些会了,你就可以飞了】
运行环境 运行环境 网页加载过程 加载资源的形式 加载资源的过程 渲染页面的过程 性能优化.体验优化 原则 从何入手 让加载更快 让渲染更快 安全 XSS跨站请求攻击 XXS攻击 XSS预防 XSRF ...
- 10个问题带你全面理解Linux性能优化
10个问题带你全面理解Linux性能优化 • Feiskyhttps://feisky.xyz/posts/2020-06-06-linux-perf/本文整理自极客时间"10个问题带你全面 ...
- Python编程规范及性能优化
为什么80%的码农都做不了架构师?>>> Ptyhon编程规范 编码 所有的 Python 脚本文件都应在文件头标上 # -*- coding:utf-8 -*- .设置编辑器 ...
- C语言嵌入式系统编程修炼之道——性能优化篇
C语言嵌入式系统编程修炼之道--性能优化篇 作者:宋宝华 e-mail:[email]21cnbao@21cn.com[/email] 1.使用宏定义 在C语言中,宏是产生内嵌代码的唯一方法.对于嵌 ...
- C语言嵌入式系统编程修炼之(六)性能优化
C语言嵌入式系统编程修炼之性能优化 使用宏定义 在C语言中,宏是产生内嵌代码的唯一方法.对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法. 写一个"标准"宏MI ...
最新文章
- 将前500页,和中间500页的CVE编号放在一起
- A+B Problem
- windows查看端口占用的进程和杀死进程
- 使用AWS使Spring Boot应用程序无服务器运行
- Dubbo思维导图知识点整理
- 负载均衡SLB中开启会话保持并选择重写Cookie时的配置方法
- python文件读写及形式转化和CGI的简单应用
- python爬虫异步加载图片_python爬虫程序 异步加载爬虫knewone.com实例
- thinkpadx1mdt 网络启动_二二、MDT 2013 Update 1批量部署-硬件驱动使用、驱动库建立及自动识别...
- Python3 语法之函数思维导图
- Oracle创建表的语法
- ANSYS网格划分简述
- Seckill学习笔记——Day3(秒杀功能实现)
- 计算机视觉-OpenCV(七)
- 数据库1NF 2NF 3NF范式解释
- 数组算法之“前缀和”
- 微信小程序实现登录获取头像昵称
- VMware安装Ubuntu-18.04.3 Server版本
- B. Partial Replacement
- 【加法器】数电中,计算机是如何运算加法的?
热门文章
- Google发布新API,支持训练更小、更快的AI模型
- 逻辑回归的向量化实现样例
- JVM - ZGC初探
- An error has occurred while drawing:java.lang.IllegalStateException: The display list is not valid.
- Android Design Support Library初探-更新中
- 日期格式php用点隔离,PHP学习之校验日期格式合法性?(使用strtotime()和date())...
- 学习笔记Hadoop(十)—— Hadoop基础操作(2)—— HDFS常用Shell操作
- python 合并区间
- php将换行变为 p 标签,editplus 将文本换行替换为p标签
- 正式环境docker部署hyperf_Hyperf使用docker-compose集群部署