CUDA系统拆解-04-warp、SIMT 与 SM:真实执行不是“线程各跑各的”
CUDA系统拆解-04-warp、SIMT 与 SM:真实执行不是“线程各跑各的”
本文是「CUDA系统拆解」系列第 04 篇。
系列导读:CUDA系统拆解-00-导读:从编程模型到 AI 推理系统的学习路线
上一篇:CUDA系统拆解-03-线程组织模型:grid、block、thread 到底在表达什么
下一篇:CUDA系统拆解-05-内存层级与访存本质:性能瓶颈为什么常卡在数据
1. 这篇解决什么问题
- 为什么写 CUDA 时看到的是
thread,但真正影响执行效率的常常是warp。 warp、SIMT、SM这些概念分别在说什么。thread、warp、block、SM到底是什么关系。- 为什么分支发散会拖慢执行。
- GPU 为什么能靠很多并发 warp 去隐藏延迟。
2. 先记住的核心结论
thread是编程模型里的基本单位,warp是执行和性能分析里的关键粒度。- 在 CUDA 语境里,一个
warp通常是32个线程一起被推进执行。 - CUDA 更准确的描述是
SIMT,不是简单的SIMD。 block是协作单位,SM是执行block和warp的核心硬件单元。- 同一个 warp 内线程行为越一致,通常执行效率越高;控制流一旦分裂,就可能发生
warp divergence。 - GPU 隐藏延迟的主要方式不是把单线程做得很强,而是让一个
SM上挂很多 warp,谁在等内存就先切去跑别的 warp。
3. 正文讲解
3.1 从线程组织走到真实执行
上一部分你已经知道:
thread / block / grid是怎么组织任务的- 一个线程如何通过索引找到自己的数据
block为什么是协作边界
但这还只是编程视角。
到了执行视角,最关键的变化是:
你写的是 thread,GPU 高效推进时主要看的却是 warp。
所以后面很多性能现象,最后都要从 warp 角度解释:
- 为什么分支会慢
- 为什么访存模式重要
- 为什么
block size常取32的倍数 - 为什么活跃 warp 不够时,延迟就会暴露出来
3.2 warp 到底是什么
可以先把 warp 理解成:
一组一起被调度、一起向前推进的线程。
你写 kernel 时,代码看起来像每个线程都在独立执行;但在底层,GPU 并不会把每个线程都当成一个完全独立的小任务去调度。更常见的做法是:
- 先把 block 内线程分组
- 每组形成一个 warp
- 再以 warp 为关键粒度发射和推进指令
这就是为什么后面分析性能时,常见问题都不是“某个线程发生了什么”,而是:
- 一个 warp 内线程是不是走了相同路径
- 一个 warp 内线程访存是不是规则
- 一个 SM 上是不是有足够多 warp 可切换
所以 warp 的意义不只是“32 个线程一组”这个定义,而是:
它是把编程层面的很多线程,映射成硬件可高吞吐执行的基本观察窗口。
3.3 什么是 SIMT,为什么它不像简单的 SIMD
这是最容易混淆的一组概念。
SIMD
- 更像“一条向量指令处理多个数据 lane”
- 常见于 CPU 的向量指令,比如 AVX、SSE
- 程序员看到的是更显式的向量化模型
SIMT
- 你写的是很多线程各自的标量代码
- 每个线程逻辑上有自己的寄存器、线程 ID、控制流
- 但硬件会尽量让同一个 warp 内线程按相似的指令流一起推进
所以二者的共同点是都在追求多数据并行。
关键区别是:
SIMD更强调“显式向量指令”SIMT更强调“线程级编程抽象 + 底层成组推进执行”
这也是 CUDA 好学但又不能只停留在语法层的原因:
表面上你写的是多个 thread,底层效率却依赖这些 thread 在 warp 内是否足够整齐。
3.4 thread、warp、block、SM 的关系
这四个概念最好一次压清楚:
thread
- 最小编程单位
- 负责一份具体计算
warp
- 关键执行粒度
- block 内线程会被拆成多个 warp
block
- 线程协作单位
- block 内可以同步,可以共享
shared memory - 一个 block 会被放到某个 SM 上执行
SM
- GPU 上负责执行 block 和 warp 的核心硬件单元
- 强调高吞吐和快速切换,不强调单线程极致低延迟
可以把关系记成:
1 | grid |
这里最关键的两句话是:
thread是你写代码时直接面对的单位warp和SM才是解释执行效率时更关键的单位
3.5 为什么 warp divergence 会带来性能损失
理想情况下,同一个 warp 内线程会沿着相同控制流一起前进。
一旦同一个 warp 内线程走了不同分支,就会出现 warp divergence。
例如一种很典型的坏模式是:
- 同一个 warp 里,部分线程走
if - 另一部分线程走
else
这时硬件通常不能让同一个 warp 在同一时刻同时执行两条完全不同的路径,只能变成:
- 先推进其中一条路径,让另一部分线程暂时不活跃
- 再推进另一条路径,让前一部分线程暂时不活跃
- 最后再汇合
这意味着什么?
- 原本可以一起推进的线程组,被部分串行化了
- warp 的有效并行度下降
- 吞吐下降
所以 warp divergence 的本质不是“分支一定错”,而是:
同一个 warp 内控制流不一致,会让原本适合成组推进的执行变得破碎。
3.6 哪些分支更容易出问题,哪些没那么可怕
更危险的分支通常有两类:
- 按线程细粒度交错分裂的分支,比如奇偶线程走不同路径
- 随机数据驱动、同一个 warp 内很容易混杂的分支
相对没那么可怕的情况:
- 同一个 warp 内大部分线程都走同一路径
- 只在边界附近少量线程发生分裂
例如最常见的边界判断:
if (idx < N)
它当然也可能让最后一个 warp 有部分线程空转,但影响通常只集中在尾部少量 warp 上。相比正确性,这个代价完全合理。
所以正确理解不是“CUDA 里不要写 if”,而是:
尽量避免把同一个 warp 切得很碎,必须分支时要知道代价在哪里。
3.7 GPU 为什么能隐藏延迟
CPU 的典型思路是:
- 尽量把单线程做快
- 靠缓存、乱序执行、分支预测去减少等待
GPU 的典型思路不是这样。GPU 更常见的做法是:
- 一个 SM 上同时挂很多 warp
- 某个 warp 因为 global memory 访问而等待时
- 不傻等,先切去执行别的 ready warp
这就是 GPU 的 latency hiding。
它的核心不是“让等待消失”,而是:
当一部分 warp 在等时,尽量保证还有别的 warp 可以继续让 SM 忙起来。
这也是为什么活跃 warp 数量很重要。
如果一个 SM 上可切换的 warp 太少,就会出现:
- 这个 warp 在等
- 那个 warp 也在等
- 没有足够的 ready warp 可以补位
最后结果就是 SM 更容易空转,吞吐下降。
3.8 为什么这些概念会直接影响后续优化
到了这里,你应该能理解几件事:
- 为什么
block size常取32的倍数,因为 block 最终会被拆成 warp - 为什么访存优化常按 warp 看,因为同一个 warp 的地址模式会影响 memory transaction
- 为什么 occupancy 有意义,因为更多活跃 warp 往往更有利于隐藏延迟
- 为什么很多 GPU 不喜欢复杂控制流,因为 warp 内控制流一碎,执行效率就会掉
所以这一篇不是在学“几个硬件名词”,而是在建立后面所有性能分析的第一层直觉。
4. 和 AI 推理的关系
这些概念和 AI 推理的关系非常直接。
GEMM、attention、LayerNorm、softmax 这类 kernel 之所以适合 GPU,本质上都是因为它们更容易形成:
- 大量规则并行
- warp 内较整齐的行为
- 可重组的访存模式
- 足够多的并发工作去喂满 SM
反过来,如果一个推理 kernel:
- 分支很多
- 数据访问很乱
- 每个 warp 干的事差异很大
那即使线程数很多,也未必高效。
所以你后面看 FlashAttention、paged attention、decode 优化时,真正要问的是:
- warp 内线程在做什么
- block 如何协作
- SM 上有没有足够多 warp 隐藏等待
5. 常见误区
thread就是执行效率分析里最关键的单位。不是,很多性能问题要落到warp上看。SIMT就等于SIMD。不是,它们都追求并行,但编程抽象和执行方式不同。warp divergence说明代码写错了。不是,问题不在“有分支”,而在同一个 warp 被切得太碎。- GPU 隐藏延迟靠的是单线程很强。不是,主要靠很多并发 warp 和快速切换。
- 线程够多就一定快。不是,还要看 warp 一致性、访存模式、资源占用和 SM 上的活跃 warp 数量。
SM就是 CPU core。不能这么机械类比,SM 更像高吞吐执行单元,不是豪华单核。
6. 复习自测
- 为什么说
thread是编程单位,warp是关键执行粒度? warp的定义是什么,它为什么重要?SIMT和SIMD的共同点与区别是什么?thread、warp、block、SM分别处在什么层次,它们之间怎么对应?- 为什么同一个 warp 内线程走不同分支会导致性能下降?
- 为什么边界判断通常不是最可怕的分支?
- GPU 是怎样依靠很多并发 warp 去隐藏延迟的?
- 为什么后面的 coalescing、occupancy、GEMM、attention 都要回到 warp / SM 视角来理解?

