[CMU 15-418] (Lecture5) perf1_ Work Distribution and Scheduling

发布时间 2023-04-25 16:36:33作者: zncleon

本系列文章为 CMU 15-418/15-618: Parallel Computer Architecture and Programming, Fall 2018 课程学习笔记
课程官网:CMU 15-418/15-618: Parallel Computer Architecture and Programming
参考文章:CMU 15-418 notes
相关资源与介绍:CMU 15-418/Stanford CS149: Parallel Computing - CS自学指南


Achieving good work distribution while minimizing overhead, scheduling Cilk programs with work stealing


Work distribution

目标:

  1. 均衡负载
  2. 降低通讯
  3. 降低额外开销

但这些目标之间是at odds with each other,所以需要根据application进行trade off

image.png


首先实现一个最简单的解决方案,然后测量他的表现,并且迭代,提升其性能

image.png


Balacing the workload

少数的不平衡会影响整体性能,限制speedup最大值

image.png


Static assignment

用指定数量的thread(worker)去完成任务,实现简单,减少运行时开销,但需要提前对每个工作的负载有一定了解
不一定要在编译器提前决定,也可以根据运行时的参数进行决定

image.png


"Semi-static" assignment

半静态分配,每隔一段时间就重新分配负载
因为这些问题的负载的变化速度都是较慢的,且相对可以预测的

image.png


Dynamic assignment

程序在运行时动态的决定任务分配
适用于 任务执行的时间与任务的总数量都是不可预测的
常使用work queue(shared / distributed)存入经过decomposition后的sub-problems(tasks / work)并且将这些任务分配给worker threads

image.png


为了平衡通讯开销,需要调整任务的粒度
更大的粒度可能会减少通讯的开销,但是也可能导致负载不均衡的问题
image.pngimage.png

image.png


为了解决末尾任务时间开销较大造成的不平衡问题
image.png
可以将大任务划分为小任务,但是这会带来更大的同步开销以及执行时间
还可以重新排序schedule任务,将任务从大到小排列
image.png


为了减少同步的开销,可以使用分布式的工作队列
每个worker一个工作队列,当本地worker工作结束,可以从其他worker队列中steal任务image.png
分布式work queue的优缺点
适用于分布式系统的计算中,但这时去其他节点偷任务的开销就比较大
本地计算会有很好的局部性,缓存
按序排列,只有前面的任务完成才会执行后面的任务
任务之间可以有一定的依赖,不必是独立的
image.png


Summary

image.png


Scheduling fork-join parallelism

image.png


Fork-join pattern: Cilk

fork-join pattern天然的适合去并行化解决一些用分治思想解决的问题
fork相当于创建一个异步执行的函数
join用于同步这些异步的函数
image.png

image.png


如果把cilk当成简单的pthread_create, pthread_join调用的话,会造成相对core而言有很多的thread并发执行,而他的context数量(支持的multi-thread数)没有这么多,就会造成context上下文切换频繁,更大的工作集造成了更小的缓存局部性

实际上是使用线程池,线程线程数量与contexts数量相同。每个线程有一个distributed work queue。
image.png


Steal

Cilk使用Run child-first(continuation stealing)
优先执行child,将后续部分放在work queue中留给其他worker来steal
优点:

  1. 执行顺序与串行执行顺序一样
  2. 不会生成大量的任务在work queue中导致空间浪费
  3. 提高了局部性

image.png


**where to steal **

本地线程将会将任务放入deque底部,这对于本地线程有更好的局部性
其他线程将会从deque顶部偷任务,顶部的任务在分治问题上的规模较大,这样就可以不用总是去偷别人的任务,减少了通讯开销
image.png


image.png


Sync
  1. no steal

下面两种方法都需要记录spawn的数量与done数量

  1. stall join: thread that initiates fork must perfrom the sync
  2. greedy policy: 初始fork的线程不一定要执行最后的sync,它在执行完自己的任务后就可以去steal其他线程的任务,由最后一个完成这一系统任务的thread进行sync

image.png


Summary

image.png