Skip to content

算子优化问题链:从一个 Kernel 到端到端收益 ​

这条问题链假设你接手了一个可以运行、但性能不稳定的算子。目标不是直接寻找“最快写法”,而是逐步确认:语义是否正确、瓶颈是否明确、局部收益能否传到模型和 workload。

算子优化:从语义到端到端验证

第一段:先写出参考实现和契约 ​

从一个简单算子或模型组件开始,明确输入 shape、dtype、stride、边界和输出误差。Part 03 的向量加法和 GEMM适合作为入口;参考实现先用 PyTorch 或 CPU 版本固定语义。

此时只回答一个问题:候选 kernel 在什么条件下算“正确”?不要先用 GPU 时间替代正确性测试。

第二段:把数据搬运路径画出来 ​

当语义契约稳定后,观察 load、计算和 store 如何映射到 global memory、L2、shared memory、register 或 Tensor Core。Part 01 的 Warp / Block / Shared Memory 和 Part 03 的 Triton 内存模型用于解释布局与 tile。

这里的判断是:候选实现减少了哪类搬运,代价又转移到了哪里?

第三段:先判断图变换是否成立 ​

在融合前先看依赖图:中间张量是否只有一个消费者、是否存在共享分支、布局转换或动态 shape,以及目标 backend 能否表达改写后的计算。常量折叠、公共子表达式消除、节点重排和 fusion 都是候选;它们只有在语义、layout 与执行约束同时满足时才进入下一段。

此时要留下一个最小图级记录:改写前后依赖、被消除的读写、需要保留的同步点,以及不满足时的 fallback。图节点变少不是性能结论。

第四段:再决定是否融合 ​

如果多个阶段反复写回中间张量,再比较 RMSNorm、Softmax 或 Attention 的融合方案:融合 RMSNorm、融合 Softmax和 FlashAttention可以作为不同复杂度的例子。

融合前先列出依赖和中间张量,融合后再检查 register、shared memory、occupancy 和边界处理。减少 kernel 数量不是充分条件。

第五段:把配置放回硬件执行模型 ​

同一个 tile 或 fusion 在不同 GPU 上可能有不同结果。使用 Part 01 的 Tensor Core,以及 Part 04 的 CUDA / Triton / PyTorch 对照和 CUDA Stream,把 dtype、shape、同步和异步搬运纳入解释。

此时才开始做 GPU microbenchmark,并固定 warmup、重复次数、GPU 和编译目标。

第六段:搜索配置并解释 trace ​

在多个 shape 或多个 GPU 上,手工选一个配置通常不够。进入 Triton Autotune 与 Profiling,比较候选 tile、warp 数和 stages,并记录编译时间、缓存命中与运行时间。

profiling 的作用是验证瓶颈假设:如果 kernel 变快但端到端不变,应该检查 launch、同步和其他阶段,而不是继续盲目调 tile。

第七段:回到 Block 和固定 workload ​

最后用 Triton Llama3 Block 项目把算子放回模型组件,再用固定 workload 比较端到端延迟、吞吐、显存、编译成本和质量。

项目报告至少保留:

  • 参考实现与候选 kernel 的语义和数值对照;
  • shape、dtype、GPU、编译目标、warmup 和重复次数;
  • kernel microbenchmark 与端到端 benchmark;
  • profiling 观察到的瓶颈和失败条件;
  • accept / tune / reject 及其证据等级。

局部 kernel 的收益只有在目标 workload 中重复出现,才可以成为端到端优化结论。

Released under the MIT License.