数据流与 ISA¶
数据流回答“数据如何在时间和空间上复用”,ISA 回答“软件可以用什么指令和同步语义要求硬件执行”。二者中间由编译器 Mapping 连接。
从 GEMM 的三个循环开始¶
矩阵乘法:
\[ C_{m,n} = \sum_k A_{m,k} B_{k,n} \]
三个循环怎样分块、展开和映射,决定 A、B、C 哪些元素留在寄存器/SRAM,哪些需要跨 NoC 或 HBM 重复搬运。
flowchart LR
ALG["算法<br/>M × N × K"] --> TILE["时间分块<br/>Tm × Tn × Tk"]
TILE --> SPACE["空间映射<br/>PE / Warp / Thread"]
SPACE --> PLACE["存储放置<br/>Register / SRAM / Cache / HBM"]
PLACE --> INST["指令选择<br/>FMA / Vector / MMA"] Stationary 描述的是什么¶
“Stationary”不是数据绝对静止,而是让某类数据在较低成本的存储层或 PE 中停留更久,以减少更高成本的数据移动。
| 数据流 | 优先驻留 | 常复用的维度 | 代价与适用倾向 |
|---|---|---|---|
| Weight Stationary | 权重 A/B | 多个输入/输出位置 | 权重复用高;部分和与输入需要移动 |
| Output Stationary | 部分和 C | K 归约 | 降低部分和读写;输入和权重广播压力可能更高 |
| Input Stationary | 输入激活 | 多个权重/输出 | 适合输入复用显著的算子 |
| Row Stationary | 行/局部窗口 | 混合复用 | 同时利用权重、输入和部分和复用,但控制更复杂 |
| No Local Reuse | 不强制驻留 | 依赖外层存储/网络 | 硬件简单,带宽与能耗压力大 |
真实 GPU kernel 往往是多级混合数据流:HBM→L2→Shared Memory→Register 的每一级都可以采用不同 Tile 和复用策略。
ISA 的三个层次¶
flowchart TB
V["虚拟/中间 ISA<br/>例如 PTX"] --> N["Native ISA<br/>例如具体 GPU 的 SASS"]
N --> U["微操作与硬件流水线<br/>实现细节通常不对软件承诺"]
M["矩阵/加速器命令<br/>MMA、DMA、Barrier"] --> N | 层次 | 稳定性 | 软件可见信息 | 典型用途 |
|---|---|---|---|
| 虚拟 ISA | 跨一组硬件代际相对稳定 | 线程、地址空间、类型、同步、目标能力 | 编译分发、JIT、向后兼容 |
| Native ISA | 绑定具体架构 | 真实指令编码、寄存器和调度信息 | 驱动执行、反汇编与性能分析 |
| 加速器命令/Tile ISA | 粒度可能高于普通指令 | 矩阵形状、DMA、Buffer、事件 | NPU/矩阵引擎的编译器 Target |
ISA 不是性能模型
ISA 定义行为,不必承诺每条指令的真实延迟、内部拆分和资源冲突。相同 ISA 在不同微架构上的吞吐可以不同,编译器仍需要 Target 信息与实测/仿真代价模型。
SIMT、SIMD 与 Systolic 的 Mapping 差异¶
| 组织 | 软件看到的单位 | 数据如何前进 | 编译器核心工作 |
|---|---|---|---|
| SIMD/Vector | 向量寄存器与固定宽度 Lane | 一条向量指令作用于多个元素 | 向量化、Tail/Mask、Layout |
| SIMT GPU | 标量 Thread,硬件组成 Warp | Warp 共同发射,线程保留独立状态 | Block/Warp Mapping、分支、合并访存 |
| Systolic Array | Tile/矩阵或命令流 | 数据沿 PE 阵列节拍传播并复用 | Tile、阵列铺排、Feed/Drain 与 Buffer |
| 数据流 NPU | Tensor/Loop + 显式 Buffer/DMA | 编译器安排搬运、计算和同步 | 多级 Tiling、双缓冲、NoC 与 Bank 规划 |
一个 Mapping 的最小描述¶
对于任一算子,至少写出以下五项:
operator: gemm
shape: {M: 4096, N: 4096, K: 4096}
dtype: {input: fp16, accumulate: fp32}
spatial_mapping: {block: [M, N], warp: [M, N]}
temporal_tiling: {M: 128, N: 128, K: 32}
memory_placement:
HBM: [A, B, C]
shared: [A_tile, B_tile]
register: [A_fragment, B_fragment, C_accumulator]
instruction: tensor_mma
这不是某个框架的固定语法,而是一份跨编译器/仿真器可对照的思考模板。它让性能问题能够追溯到 Tile、复用、容量和指令条件,而不止停留在“开启了 Tensor Core”。
Mapping 的硬约束¶
- Tile 必须放得进目标寄存器和 SRAM/Shared Memory。
- 数据类型、Layout、对齐和矩阵 Shape 必须满足目标指令要求。
- 同步必须覆盖生产者—消费者关系,不能只依赖隐式执行顺序。
- 空间展开不能超过 PE、线程或 Warp 资源;过少又会损失利用率。
- 双缓冲能隐藏搬运,但会增加 Buffer 占用并可能降低并发。
- 最小 HBM 流量不一定等于最短时间,可能牺牲并行度或增加控制开销。