每个 Streaming Multiprocessor(SM,流式多处理器) 上有多个 CUDA 核心。比如一个 SM 可能有 64、128 或更多 CUDA 核心(具体取决于架构)
block(的各个线程)不是直接“映射”到核心上
当你创建一个 block(比如 1024 个线程),这些线程被分为若干个 warp(32 个线程一组)
每次只执行 一个或几个 warp,其余的等待调度
SM 使用内部的 warp scheduler 按顺序调度这些 warp 到 CUDA 核心执行
总结:一个 block 最多可以有 1024 个“线程”,但这些线程是被调度到“共享的 CUDA 核心”上轮流执行的,而不是每个线程配一个核心
常见问题:所以threads数量和CUDA Core数量一致就能保证最大可能地利用硬件吗?不一定,threads过多过少都可能影响效率,好像没有一个一般性的选择标准?当然和warp数量(32)对齐是一定要保证的。
线程数越多(在1024的block上限内、且满足资源限制的前提下)通常越能让SM的计算核心得到更充分利用
一个block的线程越多:可以形成越多的warp(每32个线程一个warp),形成越多的warp可以提升指令发射覆盖延迟能力
但是线程调度也会带来性能消耗?每个线程都有寄存器分配、调度、上下文管理成本
让每个thread的计算“粒度”适中,即:不要太轻,不然你在浪费线程管理的成本;也不要太重,不然并行度不足
SM内部是通过 warp-level 调度的:SM每个cycle可以调度多个warp执行指令
不同显卡(不同架构)的 SM 每个时钟周期可以调度的 warp 数量是不一样的
现代GPU(如Volta/Ampere)每个SM每周期能调度多个warp,而且调度器(warp scheduler)之间是并行工作
每 32 个线程组成一个 warp,warp scheduler 把 warp 分配给 CUDA Core 来执行
绝大多数现代NVIDIA架构,SM的CUDA Core数量和warp调度器数量是配套增长的。
一个warp调度器,通常负责一组32个CUDA Core。
比如,Volta/Ampere架构每个SM有64~128个CUDA Core,4个warp调度器。
4个调度器 × 32 Core = 128个Core,这样每个调度器都能每周期各自发射一个warp,所有Core都能被充分利用。
SM里有多少Core,每个周期最多能干多少活,线程多了就是排队等着。
这就是为什么线程太多不会提升单个Block的性能,只会让排队时间变长。
但是合适增加warp数量可以更好地隐藏访存延迟,这是为什么推荐用1024线程/Block来提高SM利用率。
SM(Streaming Multiprocessor)
├── Warp Scheduler × N
├── CUDA Core × 64/128(FP32 ALU)
├── Special Function Units(SFU)
├── Load/Store Units(LD/ST)
├── Tensor Cores(如果有)
├── Shared Memory / L1 Cache
如何理解Streaming?「流」指的是什么?
首先,每个CUDA Core都是一样的,没有区别,不是CPU那样的流水线,有的取指令、有的计算之类的
在一个 SM 内的所有 CUDA Core,本质上是一组功能完全一样的 ALU(算术逻辑单元)。它们没有彼此之间的前后依赖关系,不存在“你处理前半,我处理后半”的流水线那种分工
CUDA Core 之间是“平行关系”,而不是“前后关系”
“Streaming”是逻辑概念,不是流水线关系
数据(线程)一批批地流入 CUDA Cores,按统一指令执行,然后流出,下一批继续
并不是流水线的流动,而是整体调度连续不断