推理 Kernel / Runtime 优化:少搬、少启、少等
用 HBM 流量、并行度、Kernel launch 与同步四个控制点理解 FlashAttention、Decode Kernel、Fusion 和 CUDA Graph
Kernel 优化的技术名很多,但它们主要在消除四种浪费:不必要的 HBM 往返、并行度不足、过多 launch,以及 CPU/GPU 或 GPU/GPU 同步。先识别浪费类型,比先选 FlashAttention、Fusion 或 CUDA Graph 更可靠。
- 一句话:Kernel / Runtime 优化的统一目标是少搬数据、让并行度匹配形状、少启动 Kernel、少在关键路径同步。
- 三个判断:Prefill 与 Decode 的 Attention 形状不同;Fusion/Graph 主要解决 HBM 与 launch,并不减少模型语义工作;局部加速受端到端占比和瓶颈迁移限制。
- 核心模型:
T_step ≈ max(T_compute, T_memory) + T_launch + T_sync + T_comm,优化必须指出降低了哪一项。 - 边界:具体 backend、支持算子和性能随硬件、模型形状与版本变化,本文不维护框架功能支持表。
1. 四种浪费
| 浪费 | 典型证据 | 常见控制点 |
|---|---|---|
| HBM 往返 | memory stall、高字节/FLOP、中间张量落 HBM | tiling、online reduction、fusion、低精度 |
| 并行度不足 | SM 空闲、小 Q / 小 Batch / 小 shape | split-K/V、persistent kernel、批量化 |
| Launch 过多 | GPU 间有小空隙、CPU launch 在关键路径 | fusion、CUDA Graph、批量调度 |
| 同步等待 | cudaDeviceSynchronize、D2H、collective barrier | 异步数据流、消除 host round-trip、重叠 |
这四项可能同时存在。Trace 用来定位时间,Roofline 用来判断算力/带宽,源码用来确认同步和数据依赖;单一指标不足以完成归因。
2. Attention:Prefill 与 Decode 不是同一个形状
2.1 Prefill 的 IO-aware Attention
朴素 Attention 会构造或反复访问较大的 score 中间量。IO-aware 实现通过分块和在线归约,让局部 Q/K/V 与 softmax 状态尽量留在片上存储:
加载 Q tile
→ 流式加载 K/V tile
→ 更新局部 score、max、sum、output
→ 只写最终输出
关键收益不是改变 Attention 数学定义,而是减少中间结果的 HBM 读写。序列、head dimension、mask、dtype 和硬件都会影响实际 tile 与 backend。
Attention 架构演化负责模型语义;这里讨论同一语义如何更高效执行。
2.2 Decode 的小 Q 与长 KV
单步 Decode 的 Q 很小,却要读取历史 KV。若只沿 Q 维并行,GPU 可能没有足够工作。常见方法是沿 KV 序列切分:
KV split 0 ─┐
KV split 1 ─┼→ partial attention → online reduce → output
KV split N ─┘
它以额外的 partial result 与归约换取更高并行度。是否值得取决于上下文长度、Batch、KV 布局、head 数和 backend;“使用了 FlashDecode”本身不是收益证明。
2.3 KV 布局会反向约束 Kernel
Paged KV、Prefix 共享、KV 量化和 MLA 都会改变:
- 地址是否连续;
- 每 token / block 的字节;
- Scale 或元数据读取;
- head / latent 维度;
- gather 和 dequant 是否能融合。
因此模型、内存管理和 Kernel 不是三个独立开关。KV 语义与生命周期见 KV Cache,MLA 见 DeepSeek MLA。
3. Fusion:减少中间数据和 launch
未融合的执行路径可能是:
Norm → 写 HBM
→ 读 HBM → Linear → 写 HBM
→ 读 HBM → Activation → 写 HBM
若形状、数据依赖和资源允许,融合 Kernel 可以把中间值留在寄存器或共享内存,并减少 launch:
[Norm + Linear + Activation] → 一次或更少 HBM 往返
Fusion 的代价
- 寄存器或共享内存压力可能降低 occupancy;
- 组合数量增加,编译与维护成本上升;
- 动态 shape、分支或稀有模型结构难以覆盖;
- 一个大 Kernel 更难定位局部回归;
- 通信或调度仍可能主导端到端时间。
所以判断标准不是“融合越多越好”,而是它是否降低关键路径上的字节与 launch,且没有把新瓶颈推到资源占用或编译系统。
4. CUDA Graph:降低稳定路径的 CPU 开销
普通 eager 执行由 CPU 持续发起 Kernel。若每步 Kernel 很短,CPU launch、Python/C++ runtime 和同步间隙可能可见。CUDA Graph 捕获一条稳定执行路径,之后用较少 host 操作重放。
适合:
- shape 和内存地址相对稳定;
- Decode 重复执行相似图;
- CPU launch 已在关键路径;
- 框架能管理多种 Batch / token bucket 的 graph。
不适合直接假设有效的情况:
- shape 高度动态;
- 控制流或 backend 经常变化;
- capture 需要大量 padding;
- 图管理占用过多内存;
- 真正瓶颈仍是 HBM 或通信。
Graph 优化的是运行时发射方式,不会减少模型参数或 Attention 的语义计算。
5. Compile 与专用 Kernel 怎么放进地图
编译器和手写 Kernel 都在尝试把模型图映射为更好的执行计划,但控制点不同:
| 路径 | 擅长 | 主要成本 |
|---|---|---|
| 图编译 / codegen | 跨 op fusion、常量折叠、布局与调度搜索 | 编译时间、shape specialization、fallback |
| 模板化 Kernel | 覆盖常见模型形状,迭代快 | 模板边界与版本组合 |
| 手写专用 Kernel | 对关键 shape/硬件做极致优化 | 开发、验证和可移植性 |
| Vendor library | 稳定且覆盖常见算子 | 黑盒边界、版本与形状适配 |
Serving 框架可能同时使用多条路径。框架名不能直接推出每个请求实际走了哪个 Kernel;应以构建日志、运行时选择和 Trace 为准。
6. 一个诊断顺序
6.1 确认端到端目标
- TTFT 慢:先拆 Queue、Prefill、首轮通信和采样;
- TPOT / ITL 慢:拆权重/KV 读取、Decode Attention、通信和 launch;
- 吞吐低:同时看有效 Batch、调度空洞和每步成本;
- 尾延迟高:检查动态 shape、抢占、长 Prefill、编译 fallback。
6.2 找 Top 时间块
Trace 中按时间和调用频率排序,但不要只看最慢单次 Kernel:
贡献 = 单次时间 × 调用次数 × 关键路径重叠关系
一个 20 μs Kernel 调用数万次,可能比一个 2 ms 的偶发 Kernel 更值得优化。
6.3 判断是哪类浪费
- Roofline / bytes → HBM 还是 compute;
- shape / occupancy → 并行度是否足够;
- CPU-GPU timeline → launch gap;
- sync / memcpy / collective → 等待是否可消除或重叠;
- backend 日志 / 源码 → 实际执行路径。
6.4 做最小 A/B
固定模型、Case、精度、并行和调度,只改变一个 backend 或 runtime 控制点。记录:
- 被优化时间块;
- 端到端 TTFT / TPOT / throughput;
- HBM、SM、launch、sync;
- 正确性和稳定性;
- 是否发生 fallback 或瓶颈迁移。
7. Amdahl 边界
若被优化部分占端到端时间 p,局部加速 s,理想总体加速为:
它提醒我们:
- 只看 Kernel microbenchmark 会高估服务收益;
- 优化后要重新采样,不能继续沿用旧占比;
- 调度、通信或 Queue 不在同一 Kernel benchmark 内;
- 局部时间与用户交付 token 的口径必须一致。
8. 常见误区
- FlashAttention 会让所有阶段都变快:Prefill/Decode shape 与总占比不同。
- Fusion 一定减少延迟:资源压力、动态 shape 和 fallback 可能抵消收益。
- CUDA Graph 是算力优化:它主要减少 host launch 与运行时间隙。
- 低精度 checkpoint 证明走了低精度 Kernel:必须检查实际 backend 和 Trace。
- GPU Busy 高说明 Kernel 高效:忙碌可以来自低效访存、同步或重复工作。
- 单 Kernel 快 2×,吞吐就快 2×:端到端受 Amdahl 与新瓶颈限制。
相关页面
- Compute-bound vs Memory-bound — Roofline 判断
- 推理并行 — collective、拓扑与 rank 作用域
- 批处理与调度 — shape 和有效 Batch 从哪里来
- Prefill Trace 解读 — 时间线案例
- 推理框架对比 2026 — Kernel 如何嵌入 Serving Stack
← 被以下页面引用(7)
- 推理框架对比 2026:从 Engine 到 Serving Stackai-systems · synthesis
- Kimi K3:架构、训练与推理系统研究ai-systems · synthesis
- LLM 推理系统全栈地图ai-systems · synthesis
- vLLM Async Scheduling:三态配置、投机解码与状态提交ai-systems · synthesis
- 推理并行:DP、TP、PP、EP 与 CP 怎么选ai-systems · concept
- Agentic Infra:LLM 推理性能优化与 GPU 利用率提升ai-systems · source-summary
- Hyperloom Specialist 与配置调优:一个 Agentic 调参系统的源码拆解ai-systems · source-summary
修改历史1 次提交
- docs: refine LLM inference knowledge systemxiaocheng··
f8756b9