你优化 CUDA kernel 的方式,可能一开始就错了|Kerminal 工程笔记

📅 2026/7/8 8:47:46 👁️ 阅读次数 📝 编程学习
你优化 CUDA kernel 的方式,可能一开始就错了|Kerminal 工程笔记

写在前面

在上一篇里,我们讲了一个很基础但很容易被忽略的问题:

CUDA kernel 优化失败,往往不是不会优化,而是第一步就判断错了瓶颈类型。

但在真实工程里,这句话还有一个更残酷的版本。

很多优化,其实从一开始就走错方向了。

不是因为不够熟练,而是因为:“慢”这件事,本身就有不同类型。

01GPU 里的“慢”,不一定是“慢”

如果你只盯着 runtime,会很容易产生一个错觉:

“慢就是慢,优化就是让它变快。”

但在 GPU 里,“慢”其实是不同性质的问题叠加出来的结果。

大体上,可以粗暴但有效地分成三类:

第一类,Memory-bound:不是算不动,是数据“喂不进来”。

这一类 kernel 的特征非常明确:

· global memory 访问频繁
· 访问地址不连续
· cache 命中率不高
· warp 在等待 memory
· 计算指令占比很低

典型例子比如 matrix transpose。

你会发现一件很反直觉的事情:kernel 几乎没做什么计算,但就是慢。

原因不是 GPU 不够快,而是:❗数据在“进 GPU”的过程中就已经卡住了。

这种情况下,优化的方向通常不在计算,而在数据流:

· memory coalescing 是否成立
· 数据布局是否合理
· 是否能 tile 到 shared memory
· 是否存在重复读取
· cache 是否被有效利用

一个关键点是:如果你在 memory-bound kernel 上继续优化计算路径,本质上是在“优化一个不存在的瓶颈”。

第二类,Compute-bound:不是数据慢,是算力被用满了。

这一类完全相反。这类 kernel 的特点是:

· arithmetic intensity 很高
· 大量 matrix / math / reduction
· memory 已经不再是主要瓶颈

比如 GEMM、attention 中的某些 compute-heavy path。

这时候你会看到:memory 看起来很健康,但 GPU 还是跑不满。

问题通常在计算路径:

· 是否走了 Tensor Core 路径
· 数据类型是否合理(FP16 / BF16)
· instruction 是否高效
· 是否存在重复计算
· compiler 是否做了优化
· warp-level execution 是否合理

这里有一个非常容易踩的坑:

❗继续优化 memory,在 compute-bound kernel 上通常不会带来收益

因为瓶颈根本不在那里。

第三类,Occupancy / latency-bound:不是慢,是“GPU没有忙起来”。

这一类问题最容易误判。表现是:

· compute utilization 不高
· memory utilization 也不极端
· 但整体 GPU throughput 很差

看起来“什么都不突出”,但就是慢。

本质原因是:GPU 没有足够 warp 去隐藏 latency。

常见原因包括:

· register pressure 太高
· shared memory 占用过多
· block size 不合理
· warp divergence
· sync / barrier 过多
· 并发 block 数不足

这里有一个非常关键的误解:occupancy 不是优化目标,而是结果。

很多人会把它当成调参指标,但它真正的意义是:是否足够隐藏延迟,而不是数值高低。

02大多数 CUDA 优化,其实发生在“分类之前”

如果你把这三类放在一起,会发现一个很残酷的事实:

三种 bottleneck,对应三种完全不同的优化方向。

甚至是互相冲突的:

· memory-bound → 需要减少访存
· compute-bound → 需要提升计算效率
· occupancy-bound → 需要减少资源占用

如果你分类错了,优化手段不仅没用,还可能互相抵消。

这也是为什么,很多 CUDA 优化看起来“做了很多”,但效果很有限。

03但现实工程里,还有一个更大的问题

理论上,这个方法论是清晰的:先分类,再优化。

然而,即使你掌握了这套方法论,也会遇到一个更现实的瓶颈:

kernel 太多了,而且每个 kernel 的形态都在变化。

尤其在:

· LLM training / inference
· 多 stage pipeline
· dynamic shape workload
· 多 kernel fusion system

你会逐渐发现:❗“判断 bottleneck”本身开始变成成本。

甚至在一些复杂系统里:

· profiling 一次的成本 > kernel 本身优化收益
· 人工判断速度跟不上 workload 变化
· 同一 kernel 在不同 shape 下完全不同表现

这时候问题已经开始变化了:

从“如何优化 kernel”变成“如何稳定地做出正确的优化判断”。

你会发现一个趋势:CUDA 优化正在从经验驱动,变成系统问题。

下篇预告

下一篇,我们会继续往工程现实走一步:当“bottleneck 分类”本身变得昂贵时,我们还能怎么做优化?

#CUDA#kernel优化#GPU#性能