2.6 Execution Model and GenDP ISA
论文第4.4节 Execution Model and GenDP ISA 讲的是 GenDP 加速器“怎么跑起来”:指令如何加载、PE 阵列和 PE 内部如何分工、控制指令和计算指令如何配合,以及控制指令集(ISA)长什么样。理解这一节,就能明白 GenDP 为什么能灵活支持 BSW、PairHMM、POA、Chain 这些依赖模式各不相同的 DP kernel。
下面从执行模型、控制/计算双线程、控制 ISA、数据移动示例、设计动机几个方面详细解释。
1. 整体执行模型:预加载指令 + 分层启动
GenDP 的执行模型是:
-
启动前,所有指令预加载到加速器。
- 包括控制指令和计算指令。
- 不需要运行时从外部取指,减少开销。
-
每个 PE 阵列运行一个执行线程。
- PE 阵列负责控制数据缓冲区和 PE 之间的数据移动。
- 也负责启动每个 PE 的执行。
-
PE 收到 PE 阵列发来的 start flag 后,内部启动两个线程:
- 控制线程(control thread)
- 计算线程(compute thread)
这形成了一个层级控制结构:
PE 阵列线程
├── 控制数据缓冲区
├── 控制 PE 间 systolic 数据流
└── 向每个 PE 发送 start flag
└── PE 内部
├── 控制线程
└── 计算线程
2. 控制线程 vs 计算线程
2.1 控制线程的职责
控制线程管理 数据移动:
- 在 SPM(scratchpad memory)、寄存器文件(RF)之间搬运数据;
- 控制相邻 PE 之间的 systolic 数据流;
- 控制计算线程的启动。
它不直接做目标函数的算术运算,而是负责“把数据放到正确的位置”。
2.2 计算线程的职责
计算线程执行 计算指令:
- 解码计算指令;
- 从寄存器文件加载数据;
- 在 CU 阵列中执行计算;
- 把结果写回寄存器文件。
它专注于目标函数的计算,比如取最大值、加法、乘法、查表等。
2.3 两者并行
控制线程和计算线程 并行运行。这类似于 解耦访问/执行(decoupled access-execute) 架构:
- 控制线程像“调度员”,负责搬运原料;
- 计算线程像“工人”,负责加工。
- 两者各司其职,避免计算单元因为等数据而空转。
这种设计尤其适合 POA 这种依赖模式不规则的 kernel:数据从哪里来、到哪里去,需要动态决定,控制线程可以执行分支和地址计算,灵活调度。
3. 控制 ISA(表3)
控制指令集用于 PE 阵列和 PE 内部的控制线程。表3列出了指令类型:
| 类型 | 指令 | 汇编格式 | 作用 |
|---|---|---|---|
| 算术 | add | add rd rs1 rs2 | 寄存器相加 |
| addi | addi rd rs1 #imm | 寄存器加立即数 | |
| 移动 | li | li [dest addr] #imm | 加载立即数到地址 |
| mv | mv [dest addr] [src addr] | 在存储组件间移动数据 | |
| 分支 | beq/bne/bge/blt | branch rs1 rs2 offset | 条件分支,实现循环 |
| 其他 | set | set PC | 启动下级组件 |
| no-op | no operation | 空操作 | |
| halt | halt | 停止计算 |
具体解释:
- 算术指令:操作地址寄存器,用于计算数据地址。比如
add和addi用来生成 SPM 或 RF 的访问地址。 - 移动指令:
li:把立即数加载到某个地址;mv:在寄存器文件、SPM、输入/输出端口之间搬运数据。
- 分支指令:
beq(相等跳转)、bne(不等跳转)、bge(大于等于跳转)、blt(小于跳转),用于循环迭代和条件控制。 - set 指令:控制下级组件的启动。例如:
- PE 阵列用
set启动 PE; - PE 用
set启动 CU。
- PE 阵列用
- no-op:空操作,用于对齐或延迟。
- halt:停止计算。
注意:控制指令是 手动生成 的(论文说 "The control instructions are generated manually in this work")。也就是说,编译器或设计者根据 DP kernel 的依赖模式,静态地安排好数据移动和控制流。
4. 数据移动示例(图8)
图8展示了两个相邻 PE 如何通过控制指令协作搬运数据。
-
PE[i-1] 执行:
mv [out_port null] [reg 0x00ff]意思是:把寄存器文件地址
0x00ff中的数据,移动到out_port(输出端口)。 -
PE[i] 执行:
mv [SPM 0x00ff] [in_port null]意思是:从
in_port(输入端口)读取数据,移动到 SPM 地址0x00ff。
这两个操作配合起来,就完成了 PE[i-1] 到 PE[i] 的数据传递:
PE[i-1] 的寄存器文件 → out_port → in_port → PE[i] 的 SPM
论文特别指出:
movements in both PEs are considered into the critical path and the movement can be done in one cycle.
也就是说,这两个 PE 之间的数据移动在一个时钟周期内完成,并且被计入关键路径。这意味着 systolic 数据流是周期精确的,设计时可以精确计算延迟。
5. 为什么这样设计?
5.1 解耦控制与计算
DP kernel 的依赖模式差异很大:
- BSW、PairHMM:规则的 2D 波前依赖;
- POA:图结构、长距离依赖,需要分支和动态地址;
- Chain:1D 依赖,需要广播和流水线。
如果只靠固定的 systolic 数据路径,无法满足所有需求。把控制线程独立出来,就可以:
- 用分支指令处理不规则依赖;
- 用
mv指令灵活搬运数据; - 用
set指令分层启动,协调 PE 阵列、PE、CU。
5.2 支持 VLIW 和波前并行
计算线程执行 VLIW 计算指令,每个 PE 是 2-way VLIW,可以并行执行两个计算操作。控制线程则为计算线程准备好数据,让计算单元尽量不空闲。
5.3 减少运行时开销
指令预加载,不需要运行时取指。控制指令手动生成,可以针对每个 kernel 做静态优化,减少分支和地址计算的开销。
6. 形象比喻
把 GenDP 的执行模型想象成一个工厂:
- PE 阵列 = 车间主任,负责安排原料在传送带上的流动,并通知每个工位开工。
- 控制线程 = 搬运工,负责把原料从仓库(SPM/RF)搬到工位,或者从上一个工位搬到下一个工位。
- 计算线程 = 操作工,负责在机床(CU)上加工原料。
- 控制 ISA = 搬运工的指令手册:怎么算地址(add)、怎么搬(mv)、怎么循环(branch)、怎么通知下级开工(set)。
- 计算 ISA = 操作工的指令手册:做什么运算(加法、取最大、查表等)。
搬运工和操作工同时工作,搬运工提前把原料放好,操作工就能连续加工,不会停工等料。
7. 一句话总结
第4.4节描述了 GenDP 的 分层执行模型:PE 阵列控制全局数据流和 PE 启动;每个 PE 内部并行运行 控制线程 和 计算线程,分别负责数据搬运和算术运算。控制 ISA 提供算术、移动、分支、启动等指令,手动生成,用于灵活支持各种 DP kernel 的依赖模式。这种解耦设计让 GenDP 既能处理规则的 BSW,也能应对图结构的 POA,同时保持高吞吐和能效。