CMU15418 Lecture 4: Parallel programming basics

pdf课件
本节将介绍lecture2中提到的三种通信模型(共享地址空间,消息传递,数据并行)的实际例子

今天的课不会介绍并行代码的优化,只讲讲如何构建并行程序,优化相关在后面的课程。

1 Examples of applications to parallelize

第一个例子是海洋的物理模拟,他们将3D海洋离散化为2D网格的层叠。需要计算每个网格点的物理性质随着时间的变化。
第3节中会提到如何针对2D网格做并行计算。
第二个例子是星系演化的模拟,需要计算星球之间的引力。提到了使用四叉树对星系进行表示和计算的方法。

这部分看一下就好了,没有详细研究的必要。

2 Creating a parallel program

首先明确我们并行的主要目标是什么?
提升加速比。

如何编写一个并行计算程序那?
主要分为4个步骤:

  1. (decompostion)分解问题至多个子问题(tasks)
    1. 需要分析、研究问题中可以并行的部分
    2. 目标:创建足够多的tasks,可以让机器可以充分地忙碌。
    3. 分解的关键是识别程序中的依赖。因为根据阿姆达尔准则,程序的最大加速比取决于程序的依赖。例如,假设S为程序中必须顺序执行的部分耗时的占比,那么最大加速比小于1/s,这个应该挺好理解的。
    4. 一般由程序员负责问题的分解。
  2. (assignment)将子问题(tasks)分配到并行的线程(workers)
    1. 需要考虑局部性,负载均衡等
    2. 目标:负载均衡,减少通信消耗
      1. 负载均衡和减少通信消耗是很难同时做到的,例如负载均衡最好的方法是随机分配到各个worker,但这样会使得局部性变弱,加大通信的时间。
    3. 可以一开始分配完(静态分配, 如程序员使用pthread API将tasks分配),也可以边执行,边根据情况分配(动态分配,如ISPC中tasks到线程的分配)。
    4. 一般由程序员负责(如lecture2中讲ISPC时的前两个版本),有些语言或者runtimes也会负责(如ISPC中的foreach,以及ISPC中tasks到线程的分配)
  3. (orchestration)协调多个workers的执行
    1. 需要结构化workers间的通信(如消息传递模型中消息的结构),添加同步, 组织数据在内存中的存储以减少时间消耗, 调度tasks等
    2. 目的:减少通信和同步的消耗,保留数据引用的局部性(局部性原理),减少overhead。
    3. 实现和细节依赖于使用的通信模型,编程抽象,如共享地址空间还是消息传递等。
    4. 硬件细节会影响该过程。例如,如果同步消耗很大的话,需要减少它的使用。
  4. (mapping)将workers分配到具体的硬件上执行。
    1. 需要考虑局部性,硬件特性等
      1. 相关线程放到一个处理器或者core可以更好地利用局部性,减少通信和同步的消耗
      2. 不相关的线程放到一个处理器或者core可以使得机器运行的更加高效,如一个是计算型线程,一个是IO型线程。
    2. 目的:将workers放置到具体的机器执行单元
    3. 操作系统,编译器,硬件,程序员都可以负责这个部分
      1. 操作系统负责:将线程分配到哪个core
      2. 编译器负责:将ISPC的程序实例映射到向量指令
      3. 硬件负责:将CUDA线程放置到GPU cores
      4. 程序员负责:设置线程对core的亲和性,可以使操作系统将线程分配到指定core。

当我们说一个问题的计算量很大时,该问题有三种类型,分别是计算型,数据型和混合型。
旅行商问题就是计算型,它的数据就只有几十个坐标,但需要很大的计算量。
而计算几百亿个数的sin,则属于数据型,单个数的sin计算很快,计算量大是因为数据多。
而对几亿个数的排序,是混合型,数据和计算是混在一起的。
面对一个问题,我们可以尝试从计算和数据两个维度对问题进行分解。

3 A parallel programming example

3.1 A 2D-grid problem

本节将以一个2D网格的偏微分方程计算为例(简化了的海洋模拟),分析并行编程的步骤,并且使用lecture 2提到的3种通信模型进行并行编程。
我们的目标如下图,即多次对全图中的每个点进行右边的计算,直到全图收敛。


image.png

首先给出一个最简单的,非并行的算法:


image.png

我们将在这个基础上进行并行。

3.1.1 decomposition

首先,我们要分析他并行的可能性,我们可以看到对角线计算时是可以并行的,如下图:


image.png

但这种并行的潜力太小了,一次还是只能计算一条对角线,并且需要频繁地同步。

实际上,我们可以改变算法,使得该算法可以更好地并行,但这个改变需要我们对这个偏微分方程有足够的理解。
新的方法是将网格分为红色和黑色,先并行计算红色格子,计算完后再计算黑色格子,这样多次迭代,直到收敛,如下图:


image.png

3.1.2 assignment

然后,如何将计算分配到不同的works? 这里有两个方法,分别是分块型和交叉型,如下图:


image.png

右边的Px表示将该行分配到对应的work。

两者谁更好取决于运行的系统。(??这里没完全理解)

我们来看一下该并行的运行过程:

  1. 首先更新红色节点
  2. 等待所有红色节点更新完成
  3. 多个处理器之间通信,同步红色节点的更新数据
  4. 更新黑色节点
  5. 等待所有黑色节点更新完成
  6. 多个处理器之间通信,同步黑色节点的更新数据
  7. 重复

我一开始很疑惑为什么有步骤3,6,不都是存在内存里吗?然后我意识到他这里讲的是多处理器,甚至多机的情况。单处理器的时候,多个core之间有缓存一致性,因此多个线程之间根本不需要显式地通信。而多处理器和多机器时,就需要显式通信了 .
update:就算单处理器,缓存一致性也是需要耗时间的,也能算一种通信吧。

3.1.3 orchestration

我们来看一下不同分配方式下workers之间的协作。


image.png

灰色部分是每次迭代时,需要发送到P1的数据,如当P2开始计算第一行时,需要知道P1中第三行的数据(可以认为,现在讨论的是多机器的情况,他们不是共享地址空间的,每个机器只有当前计算部分的数据)
可以看到左图的通信比右图少很多,因此在大多数情况下,左图更好。

接下来,我们分别将用三种通信模型实现并行。

3.2 Data-parallel solver

下图是数据并行的伪代码,数据并行的特点是编程语言和runtime为你做了很多工作,你不需要去写具体的实现代码,你只需要声明什么地方你想做什么事即可。


image.png

3.3 Shared address space solver with SPMD

在共享地址空间模型中程序员负责同步,需要在临界区lock以便线程互斥进入,并在合适的地方设置barriers以便线程可以在此处停下。
具体代码如下:


image.png

barrier是一个同步原语,用来表达依赖关系。barrier可以将计算划分为几个步骤,只有所有线程在barrier前都完成了计算,才能继续执行之后的代码。

上面这个代码很简单,但有性能问题,红框中每一次计算都需要互斥一下,因此我们可以对每个线程设置一个diff的临时变量,在计算完成后汇总所有的diff结果,如下图:


image.png

现在,总结一下数据并行模型和共享地址空间模型:

  1. 数据并行
    1. 同步:单个线程,没啥同步
    2. 通信:隐式地load和store(和共享地址空间一样);或者更加复杂的内置通信原语,如reduce
  2. 共享地址空间
    1. 同步:共享变量的互斥访问;使用barriers表达依赖(不同的计算阶段间)
    2. 通信:隐式地load和store(和共享地址空间一样)

3.4 Message-passing solver

我们假设每个线程都有自己的私有地址空间,线程间的通信需要使用send和receive发送消息。
每个线程只有属于自己的数据,如下图:


image.png

当所有红色节点计算完成后,开始计算黑色节点。此时,线程1和线程3要将某些行的数据发送给线程2,用于计算线程2的数据中边缘行的数据,如下图:


image.png

因此,整个程序大致是这个样子:


image.png

上面的send和recv的调用是阻塞的,也就是说在数据没发送完或接收完,并对方给答复之前,他们不会返回,如下图:


image.png

然而,上面的程序会死锁,因为线程们一开始都是send,而不是recv。而如果没有recv的话,send是不会return的,大家就一起死锁了。因此,我们要将一开始的send,recv改一下,使得大家不是都从send开始,如下:

if(tid%2==0){
    sendDown();recvDown(;
    sendup(); recvUp();
}else{
recvUp(); sendUp();
recvDown();sendDown();
}

上面介绍了阻塞型的send和recv,实际上还有非阻塞型的,他们可以在调用后不等对方的确认就立刻返回, 调用线程可以做其他的事。
主程序可以使用checksend,checkrecv检测是否发送或接收完毕。如下图:


image.png

4 总结

  1. 首先介绍了阿姆达尔定律,即并行的最大加速比取决于程序中必须顺序执行的部分的耗时占比
  2. 介绍了编写并行程序的步骤,分别是分解problem至tasks,分配tasks到workers,然后协调各个workers之间的通信和同步,最后将workers放置到具体的物理设备。

今天我们关注的是如何识别程序依赖
马上我们要介绍识别局部性,和减少同步。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容