跳转至

数据流与 ISA

数据流回答“数据如何在时间和空间上复用”,ISA 回答“软件可以用什么指令和同步语义要求硬件执行”。二者中间由编译器 Mapping 连接。

从 GEMM 的三个循环开始

矩阵乘法:

\[ C_{m,n} = \sum_k A_{m,k} B_{k,n} \]
for m in M:
  for n in N:
    for k in K:
      C[m, n] += 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 流量不一定等于最短时间,可能牺牲并行度或增加控制开销。

延伸阅读