高性能科学计算理论和方法课件:第三章PPT.ppt
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《高性能科学计算理论和方法课件:第三章PPT.ppt》由用户(罗嗣辉)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 性能 科学 计算 理论 方法 课件 第三 PPT
- 资源描述:
-
1、用MPI进行分布式内存编程 分布式内存系统共享内存系统Hello World! (a classic)标注MPI进程n在并行编程中,将进程按照非负整数来进行标注是非常常见的。n如果有p个进程,则这些进程将被编号为0,1,2, ,p-1。n第一个MPI程序MPI程序n首先,这是一个C语言程序, 它包含了C语言的标准头文件stdio.h和string.h,它还有一个像其他C语言程序一样的main函数。n包含了mpi.h头文件。头文件包括了MPI函数的原形、宏定义、类型定义等,它还包括了编译MPI程序所需要的全部定义与声明。n所有MPI定义的标识符都由字符串MPI_开始。下划线后的第一个字母大写,表
2、示函数名和MPI定义的类型。MPI定义的宏和常量的所有字母都是大写的,这样可以区分什么是MPI定义的,什么是用户程序定义的。MPI的组成nMPI_Initn告知MPI系统进行所有必要的初始化设置.nMPI_Finalizen告知MPI系统MPI已经使用完毕,为MPI而分配的任何资源都可以释放了.MPI基本框架通信子n在MPI中,通信子(communicator)指的是一组可以互相发送消息的进程集合nMPI_Init的其中一个目的,是在用户启动程序时,定义由用户启动的所有进程所组成的通信子。这个通信子称为MPI_COMM_WORLD通信子通信子的进程数my rank (正在调用的进程在通信子中的
3、进程号)单程序多数据流(SPMD)n单程序多数据流(Single Program,Multiple Data,SPMD)n注意,我们刚才编译的是单个程序,而不是为每个进程编译不同的程序.n0号进程本质上做的事情与其他进程不同.n当其他进程生成和发送消息时,它负责接收消息并打印出来.nif-else语句使得我们的程序是SPMD的.通信n在第17行和第18行中,除了0号进程外,每个进程都生成了一条要发送给0号进程的消息n第19行和第20行代码将消息发送给0号进程。另一方面,0号进程只是用printf函数简单地将消息打印出来,然后用一个for循环接收并打印由1、2、comm_sz-1号进程发送来的消
4、息n第24行和第25行接收由q号进程发送来的消息,其中,q=1、2、comm_sz-1。通信发送消息前三个参数,msg_buf_p、msg_size和msg_type定义了消息的内容。剩下的参数,dest、tag和communicator定义了消息的目的地。通信发送消息n我们注意到,字符串greeting的大小与msg_size和msg_type所指定的消息的大小并不相同。例如,每条消息的长度为31个字符,但我们分配长度为100个字符的缓冲区来存储greeting字符串。当然,发送消息的大小必须小于或等于缓冲区的大小。通信发送消息n第四个参数dest指定了要接收消息的进程的进程号。第五个参数t
5、ag是个非负int型,用于区分看上去完全一样的消息。通信发送消息nMPI_Send的最后一个参数是一个通信子。所有涉及通信的MPI函数都有一个通信子参数。数据类型通信接收消息前三个参数指定了用于接收消息的内存:msg_buf_p指向内存块,buf_size指定了内存块中要存储对象的数量,buf_type说明了对象的类型。后面的三个参数用来识别消息消息匹配MPI_Sendsrc = qMPI_Recvdest = rrq接收消息n接收者可以在不知道以下信息的情况下接收消息:n消息中的数据量,n消息的发送者,n或者消息的标签.status_p参数MPI_SOURCEMPI_TAGMPI_ERROR
6、MPI_Status*MPI_Status* status;status.MPI_SOURCEstatus.MPI_TAG能接收多少数据?MPI_Get_count(&status, recv_type, &count)MPI_Send和MPI_Recv的语义n当我们将消息从一个进程发送到另一个进程时,会发生什么?一般来说,发送进程组装消息,例如,它为实际要发送的数据添加“信封”信息。n一旦消息组装完毕,如第2章所说,有两种可能性:发送进程可以缓冲消息,也可以阻塞(block)。MPI_Send和MPI_Recv的语义nMPI_Send的精确行为是由MPI实现所决定的n典型的实现方法有一个默认
7、的消息“截止”大小(“cutoff” message size)。如果一条消息的大小小于“截止”大小,它将被缓冲;如果大于截止大小,那么MPI_Send函数将被阻塞。n与MPI_Send不同,MPI_Recv函数总是阻塞的,直到接收到一条匹配的消息。潜在的陷阱n如果一个进程试图接收消息,但没有相匹配的消息,那么该进程将会被永远阻塞在那里,即进程悬挂n如果调用MPI_Send发生了阻塞,并且没有相匹配的接收,那么发送进程就悬挂起来用MPI来实现梯形积分法梯形积分法梯形积分法如果称最左边的端点为x0,最右边的端点为xn,则有:串行程序的伪代码并行化梯形积分法n回想一下,可以用四个基本步骤去设计一个
8、并行程序:n1)将问题的解决方案划分成多个任务。n2)在任务间识别出需要的通信信道。n3)将任务聚合成复合任务。n4)在核上分配复合任务。梯形积分法的任务和通信n对于梯形积分法,我们可以识别出两种任务:一种是获取单个矩形区域的面积,另一种是计算这些区域的面积和。然后利用通信信道将每个第一种任务与一个第二种任务相连接并行伪代码/我们简单地假设comm_sz能整除n,则这个程序的伪代码如下所示注意n注意,我们对标识符的选择,是为了区分局部变量与全局变量。局部变量只在使用它们的进程内有效。梯形积分法程序中的例子有:local_a、local_b和local_n。如果变量在所有进程中都有效,那么该变量
9、就称为全局变量。该程序中的例子有:变量a、b和n。First version (1)First version (2)First version (3)I/O处理n现有版本的并行梯形积分法程序有个严重的不足:它只能用1024个梯形计算0,3区间内的积分。与简单地输入三个新值相比,编辑和重新编译代码这种做法的工作量相当大。因此我们需要解决用户输入的问题。当讨论并行程序输入的同时,我们也一并将输出问题考虑进来。输出n在“问候”程序和梯形积分法程序中,假定0号进程将结果写到标准输出stdout,即它对printf函数的调用是我们所希望的行为n几乎所有的MPI实现都允许MPI_COMM_WORLD里的
10、所有进程都能访问标准输出stdout和标准错误输出stderr,所以,大部分的MPI实现都允许所有进程执行printf和fprintf(stderr,)。输出n但是,大部分的MPI实现并不提供对这些I/O设备访问的自动调度。也就是说,如果多个进程试图写标准输出stdout,那么这些进程的输出顺序是无法预测的,甚至会发生一个进程的输出被另一个进程的输出打断的情况。n例如,假设运行一个MPI程序,每个进程只是简单地打印一条消息输出例子每个进程只是简单地打印一条消息.Running with 6 processesunpredictable output输出n这一现象产生的原因是MPI进程都在相互“
11、竞争”,以取得对共享输出设备、 标准输出stdout的访问。我们不可能预测进程的输出是以怎样的顺序排列。这种竞争会导致不确定性,即每次运行的实际输出可能会变化。输入n与输出不同,大部分的MPI实现只允许MPI_COMM_WORLD中的0号进程访问标准输入stdin。n例如,在梯形积分法的并行程序中的Get_input函数,0号进程只是简单地读取a、b和n的值,并将这三个值发送给其他每个进程。除了0号进程发送数据给其他进程、其他进程只是接收数据外读取用户输入的函数读取用户输入的函数n为了使用该函数,我们可以在主程序中简单地插入对该函数的调用。要注意的是,我们必须在初始化my_rank和comm_
12、sz后,才能调用该函数:集合通信树形结构通信n想一想我们编写的梯形积分法程序,我们就会发现几件可以提高程序性能的事。其中最明显的就是在每个进程都完成了它那部分积分任务之后的“全局求和”(global sum)。n正如我们在第1章中见到的那样,可以使用一棵像图3-6所描绘的二叉树结构。树形结构通信树形结构通信n在图3-6中,一开始1号进程、3号进程、5号进程、7号进程将它们的值分别发送给0号进程、2号进程、4号进程、6号进程。然后0号进程、2号进程、4号进程、6号进程将接收到的值加到它们自己原有的值上,整个过程重复两次:n1)a. 2号进程和6号进程将它们的新值分别发送给0号进程和4号进程。n
13、b. 0号进程和4号进程将接收到的值加到它们的新值上。n2)a. 4号进程将它最新的值发送给0号进程。n b. 0号进程将接收到的值加到它最新的值上。另外的配对方式MPI_Reducen由于存在各种可能性,指望MPI程序员都能编写出最佳的全局求和函数是不合理的。所以,MPI中包含了全局求和的实现,以便帮助程序员摆脱无止境的程序优化。n“全局求和函数”需要通信。然而,与MPI_Send函数和MPI_Recv函数两两配对不同,全局求和函数可能会涉及两个以上的进程。事实上,在梯形积分法程序中,它涉及MPI_COMM_WORLD中所有的进程。MPI_Reducen在MPI里,涉及通信子中所有进程的通信
14、函数称为集合通信(collective communication)。n为了区分集合通信与类似MPI_Send和MPI_Recv这样的函数,MPI_Send和MPI_Recv通常称为点对点通信(pointtopoint communication)。MPI_Reducen全局求和函数只是集合通信函数类别中的一个特殊例子而已。例如,我们可能并不是想计算分布在各个进程上的comm_sz值的总和,而是想知道最大值或最小值,或者总的乘积,或者其他许多可能情况中的任何一个所产生的结果nMPI对全局求和函数进行概括,使这些可能性中的任意一个都能用单个函数来实现:MPI_Reducen这个函数的关键在于第5
15、个参数,operator。它的类型为MPI_Op,是一个像MPI_Datatype和MPI_Comm一样的预定义MPI类型。这个类型有多个预定义值MPI_ReduceMPI_Reducen在梯形积分法程序中,我们要使用的运算符为MPI_SUM,将这个值赋给operator参数后,就可以将梯形积分法程序中的第1828行的代码用单个函数调用代替:MPI_Reducen如果count参数大于1,那么MPI_Reduce函数可以应用到数组上,而不仅仅是应用在简单的标量上。下面的代码可以用于一组N维向量的加法,每个进程上有一个向量:集合通信vs.点对点通信n在通信子中的所有进程都必须调用相同的集合通信函
16、数。n例如,试图将一个进程中的MPI_Reduce调用与另一个进程的MPI_Recv调用相匹配的程序会出错,此时程序会被悬挂或者崩溃。集合通信vs.点对点通信n每个进程传递给MPI集合通信函数的参数必须是“相容的”。n例如,如果一个进程将0作为dest_process的值传递给函数,而另一个传递的是1,那么对MPI_Reduce调用所产生的结果就是错误的,程序可能被悬挂起来或者崩溃。集合通信vs.点对点通信n参数output_data_p只用在dest_process上。n然而,所有进程仍需要传递一个与output_data_p相对应的实际参数,即使它的值只是NULL。集合通信vs.点对点通信
17、n点对点通信函数是通过标签和通信子来匹配的。n集合通信函数不使用标签,只通过通信子和调用的顺序来进行匹配。例如,看看表3-3所示的MPI_Reduce调用例子(1)假设每个进程调用MPI_Reduce函数的运算符都是MPI_SUM,那么目标进程为0号进程。粗略地看一下整张表,在两次调用MPI_Reduce后,b的值是3,而d的值是6。例子(2)n但是,内存单元的名字与MPI_Reduce的调用匹配无关,函数调用的顺序决定了匹配方式。n所以b中所存储的值将是1+2+1=4,d中存储的值将是2+1+2=5。别名问题n我们也许会冒风险使用同一个缓冲区同时作为输入和输出调用MPI_Reduce。例如,
18、我们想求得所有进程里x的全局总和,并且将x的结果放在0号进程里,也许会试着这样调用:别名问题n但在MPI里,这种调用方式是非法的。它的结果是不可预测的:它可能产生一个错误结果,也可能导致程序崩溃,但也可能产生正确的结果。n它之所以是非法的,主要原因是它涉及输出参数的别名。两个参数如果指向的是同一块内存,它们之间就存在别名问题。MPI禁止输入或输出参数作为其他参数的别名。MPI_Allreducen梯形积分法程序中,我们只打印结果,所以只用一个进程来得到全局总和的结果是很自然的。n然而,不难想象这样一个情况,即所有进程都想得到全局总和的结果,以便可以完成一个更大规模的计算。n例如,用一棵树来计算
19、全局总和,我们可以通过“颠倒”(reverse)整棵树来发布全局总和MPI_AllreducenMPI提供了一个MPI_Reduce的变种,可以令通信子中的所有进程都存储结果:参数表其实与MPI_Reduce的是相同的,除了没有dest_process这个参数,因为所有进程都能得到结果Broadcastn在梯形积分法程序中,如果用树形结构的通信来代替0号进程的循环接收消息,从而提升全局求和的性能,那么我们应该也可以将类似的方法用于输入数据的发布。n事实上,如果简单地在树形全局求和里“颠倒”通信,我们可以得到如图3-10所示的树形结构通信图,并且能够将这个结构用于输入数据的发布。A tree-s
20、tructured broadcast.Broadcastn在一个集合通信中,如果属于一个进程的数据被发送到通信子中的所有进程,这样的集合通信就叫做广播(broadcast)。MPI的广播函数:进程号为source_proc的进程将data_p所引用的内存内容发送给了通信子comm中的所有进程。Broadcastn修改Get_input函数,用MPI_Bcast函数,来取代MPI_Send和MPI_Recv函数。Broadcastn对MPI_Bcast函数,data_p参数在进程号为source_proc的进程中是一个输入参数,在其他进程中是一个输出参数。n因此,当集合通信函数中的某个参数被标
21、记为输入/输出(in/out)时,意味着可能在某些进程中它是输入参数,而在其他进程中是一个输出参数。数据分发n如果我们想编写一个程序,用于计算向量和:用串行加法来计算向量求和如何用MPI实现这个程序呢?n计算工作由向量的各个分量分别求和组成,所以我们可能只是指定各个任务求和的对应分量。这样,各个任务间没有通信,向量的并行加法问题就归结为聚合任务以及将它们分配到核上。n如果分量的个数为n,并且我们有comm_sz个核或者进程,那么可以简单地将连续local_n个向量分量所构成的块,分配到每个进程中。向量的划分n表3-4的左4列显示了当n=12且comm_sz=3时的例子。这种做法通常称为向量的块
22、划分。向量的划分n向量块划分的另一个方法是循环划分。在循环划分中,我们用轮转的方式去分配向量分量。0号进程得到了向量的0号分量,1号进程得到了1号分量,2号进程得到了2号分量,0号进程又得到了3号分量,以此类推。向量的划分n第三种划分方法叫块-循环划分。基本思想是,用一个循环来分发向量分量所构成的块,而不是分发单个向量分量。所以首先要决定块的大小。向量求和的并行实现n一旦决定如何划分向量,就能很容易地编写向量的并行加法函数:每个进程只要简单地将它所分配到的向量分量加起来。散射n现在假设我们想测试向量加法函数。先读取向量的维度,然后读取向量x和向量y是很方便的。n如何分配向量分量:0号进程读入向
23、量,然后将它们广播给其他进程?散射n但这种方法很浪费。如果有10个进程,向量有1万个分量,那么每个进程都需要为1万个分量的向量分配存储空间,但每个进程只在含有1000个分量的子向量上进行操作。n例如,假设我们使用块划分法,那么如果0号进程只是将10001999号分量发送给1号进程,将20002999号分量分配给2号进程,以此类推。用这种方法,19号进程将只需要为它们实际使用的向量分量分配存储空间。散射n因此,0号进程读入整个向量,但只将分量发送给需要分量的其他进程。散射n如果通信子comm包含comm_sz个进程,那么MPI_Scatter函数会将send_buf_p所引用的数据分成comm_
24、sz份,第一份给0号进程,第二份给1号进程,第三份给2号进程,以此类推。n例如,假如我们使用块划分法,并且0号进程已经将一个有n个分量的向量整个读入send_buf_p中,则0号进程将得到第一组local_n=n/comm_sz个分量,1号进程将得到下一组local_n个分量,以此类推。散射n每个进程应该将它本地的向量作为recv_buf_p参数的值,将local_n作为recv_count参数的值。send_type和recv_type参数的值都应该是MPI_DOUBLE,src_proc参数的值应该是0。n注意:send_count参数的值也应该是local_n,因为send_count参
展开阅读全文