Codelet调度模型与Swdarts
Codelet程序执行模型
基本单元
- codelet程序执行模型的基本调度和执行单元
- 一个codelet是一些机器指令的集合(代码片段)
- codelet一旦开始执行,不会被中断或迁移
- codelet中不包括延迟时间长或等待的操作
- codelet间异步、并发,产生若干token(数据)作为输出
激发规则
- 休眠状态:数据依赖未满足
- 就绪状态:数据依赖满足
- 激发状态:有空闲的计算单元且事件依赖被满足
- 完成状态:完成计算
Codelet Graph
计算任务被划分成大量的codelet, 这些codelet及其依赖关系构成一张数据流图,称位Codelet Graph(CDG)。CDG是一个有向无环图。
CDG被划分为一个个子图,每个子图被分配一个Threaded Procedure(TP),由TP对其调度和执行。
Threaded Procedure
TP是异步的函数,以控制流的方式被调用,包括一个上下文框架和CDG子图。
- 上下文框架:为CDG中的codelet提供所需所有数据操作服务(初始化输入数据、为中间数据分配和释放空间、输出数据分配空间)
- TP被实例化后,绑定到一个核簇(cluster)上。TP的CDG子图中所有codelet被分配给该cluster调度执行。
- TP被实例化之前可以在cluster间迁移,以进行负载平衡。一旦被分配给一个cluster后,TP便不可移动。
抽象机器模型
抽象机器系统由若干计算节点(node)构成,计算节点以互联网络连接。每个计算节点由一个或者多个many-core chip构成,节点内chip以高速开关或总线互联。
Chip上的cluster以片上网络互联,每个cluster上有多个core。core分为计算单元(CU)和调度单元(SU)。CU负责执行codelet,SU负责:(1) 管理cluster所有硬件资源 (2) 在cluster间调度TP (3) 将处于就绪态的codelet依据一定调度策略给合适的CU执行。
Swdarts
抽象机器模型
为了利用申威众核异构平台,需要将Codelet抽象机器模型映射到国产异构众核平台上。
- 核组即可映射为Codelet抽象机器模型中的cluster,包含两种不同功能的core:
- 主核:调度单元,负责任务分配和调度
- 从核:计算单元,负责任务计算
Runtime system设计与实现
Runtime system主要负责任务的分配调度和任务间通信,是核心组件。
整个系统分为两层:
- 用户层:提供给用户描述、生成、调度可执行任务的接口,用户通过所提供接口对应用程序进行数据流风格的抽象,并使用接口将可执行任务交给下一层
- 运行时执行层:负责将以满足数据依赖关系的计算任务分配给空闲的硬件资源
- 设置了任务队列,入队的任务表示依赖关系已经满足
前端接口设计
- Task类:所有任务的抽象基类
- 主要包括计算任务需要的上下文数据、可并行的计算任务、任务之间的数据依赖(CDG子图)
- 对应Codelet中的TP
- 可以发起生成一段可以并行执行的tasklet和task任务
- 需要维护任务之间的链接关系来维护上下文数据的生命周期
- execute(): task的执行函数,函数中可以做计算,也可以启动其他并行任务(task, tasklet),再次声明任务之间的依赖关系
- invoke(task) 启动并行执行的task任务
- spawn_task(task_ptr) 将满足依赖关系的task任务放到任务队列中
- Tasklet类:对应codelet,是运行时系统中的基本执行和调度单元
- tasklet无需维护上下文数据,只需管理tasklet任务间的依赖关系
- tasklet组成:依赖计数、执行函数、通知函数
- spawn_tasklet(tasklet_ptr): 将tasklet放入tasklet队列中
- release(): 释放tasklet的依赖计数,当计数为0时,调用spawn_tasklet()函数
- execute(): 执行函数,执行过程调用激发函数,通过上述函数声明tasklet之间的依赖关系(??)
- can_spawn_on_cpe(): 表示tasklet在主核上还是从核上执行
- enable_cpe_spawn类:与tasklet类基本相同,定义为可以在从核上运行的代码,只有执行函数
- 创建该类原因:tasklet或enable_cpe_spawn依赖计数减为0时,被放入任务队列。依赖计数操作和通知操作会放在主核上执行,但是从核如果可以依赖计数操作和通知操作,需要对主核队列进行读写原子操作,代价大、成本高。
- spawn__(): 主从核之间的任务传递,并在从核上执行计算任务
- 创建该类原因:tasklet或enable_cpe_spawn依赖计数减为0时,被放入任务队列。依赖计数操作和通知操作会放在主核上执行,但是从核如果可以依赖计数操作和通知操作,需要对主核队列进行读写原子操作,代价大、成本高。
- Runtime类:要负责任务的调度和执行,以及判断tasklet任务是否可以放到从核上执行,由用户声明。
- make_tasklet(): 用于将函数定义或转换为tasklet
- execute_and_wait(): 用于启动运行时系统和定义运行时系统停止的条件,并将数据流抽象化的应用交给运行时系统。
- launch(Args…): 用户构造task时,通过launch()函数将任务需要的上下文传递给task
运行时系统设计
运行时系统:负责任务分配调度和执行;负责启动、管理从核
- 给从核队列中每个从核设置三种状态:初始化、空闲和繁忙
- 从核完成tasklet计算任务后,主核完成tasklet的通知任务,并将满足数据依赖的任务push到对应任务队列中
- 循环检查task任务队列,将队首任务取出并执行;循环检查tasklet任务队列,将队首tasklet根据用户声明交给主核或从核执行
运行时系统执行流程:
- 用户完成应用的数据流化抽象,通过接口交给运行时系统
- 将满足依赖关系的任务放入任务队列
- 查询从核阵列状态,如果有空间资源,将任务分配计算
- 从核计算完成,改变对应从核状态
继承关系
- std::enable_shared_from_this<task>
- task
- tasklet
- mem_fn_tasklet
- task_context
- tasklet
- task
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 AFlyingSheep's Blog!
评论