2155 字
11 分钟
CUDA 执行模型
2026-07-18
无标签

概述#

  • 理解线程束执行的本质

    • 掌握线程束(Warp)作为 GPU 基本调度单位的执行机制
    • 理解线程束内 32 个线程的 SIMT(单指令多线程)执行模式
    • 识别线程束分支发散对性能的影响
  • 增大 GPU 的并行性

    • 提高线程级并行度以隐藏内存延迟
    • 平衡计算资源与内存带宽的利用率
    • 通过增加活跃线程束数量提升 GPU 占用率(Occupancy)
  • 掌握网格和线程块的启发式配置

    • 根据 GPU 架构特性选择最优线程块大小
    • 利用线程块维度与 Warp 大小的对齐关系
    • 针对数据规模和 SM 数量调整网格尺寸
  • 学习多种 CUDA 的性能指标和事件

    • 使用 CUDA 事件(Event)精确测量核函数执行时间
    • 利用 NVIDIA Visual Profiler / Nsight Compute 分析性能瓶颈
    • 关注内存吞吐量、计算吞吐量、占用率等关键指标
  • 了解动态并行与嵌套执行

    • 掌握设备端启动核函数(Kernel Launch from Device)的机制
    • 理解父子网格的同步与内存可见性规则
    • 识别动态并行适用的递归算法场景与开销权衡

SIMT#

GPU的并行结构#

  • SM(流式多处理器) 是GPU的基本计算单元,每个SM可同时执行数百个线程
  • 一个GPU通常包含多个SM,因此整体可同时执行数千个线程
  • 内核启动后,线程块被分配到可用的SM上执行
  • 线程块一旦绑定到某个SM,其线程只能在该SM上运行
  • 多个线程块可以共享同一个SM,具体取决于该SM的剩余资源

线程束(Warp)#

  • CUDA采用 SIMT(单指令多线程) 架构
  • 32个线程 组成一个线程束(warp)
  • 同一线程束内的所有线程同步执行相同指令
  • 每个线程拥有独立的:
    • 指令地址计数器
    • 寄存器状态
    • 执行路径(允许分支发散)

SIMT vs SIMD#

SIMDSIMT
执行模式向量元素强制同步执行线程可独立执行
灵活性低,一个同步组内必须一致高,允许同一线程束内线程走不同分支
适用场景数据并行,无分支线程级并行,允许条件判断

为什么32是关键数字#

  • 32是SM以SIMD方式同时处理的工作粒度
  • 线程数量按32对齐时,硬件资源利用率最高
  • 非32倍数会造成线程束内部分线程空闲,降低效率

SIMT的三个核心特征(SIMD不具备)#

  1. 每个线程有独立的指令地址计数器
  2. 每个线程有独立的寄存器状态
  3. 每个线程可以有独立的执行路径

为什么需要 Warp?#

Block是软件层面的组织单位,Warp是硬件层面的执行单位。两者不在同一个维度。

Block(线程块)Warp(线程束)
层面软件/编程模型硬件/执行模型
作用程序员组织线程的逻辑单元GPU实际调度和执行线程的物理单元
大小程序员自定义(1~1024线程)固定32线程,由硬件决定
是否可选必须显式定义硬件自动划分,程序员通常不直接操控

为什么不把Warp做成1024线程?#

1. 寄存器资源限制#

每个线程需要独立的寄存器状态。假设每个线程用32个寄存器:

Warp大小单Warp所需寄存器一个SM的寄存器总量(典型值)结论
32线程1024个65536个一个SM可同时容纳64个Warp
1024线程32768个65536个一个SM只能同时容纳2个Warp

Warp太大 → 同时活跃的Warp数量锐减 → 无法通过Warp切换隐藏内存延迟

GPU隐藏延迟的核心机制就是快速切换Warp:当一个Warp等待内存数据时,SM立刻换另一个Warp执行。如果SM上只有2个Warp,一个等内存时另一个也在等,SM就空转了。


2. 分支发散(Divergence)的代价#

SIMT架构下,同Warp内线程走不同分支时必须串行执行

if (threadIdx.x % 2 == 0) {
A(); // 偶数线程执行
} else {
B(); // 奇数线程执行
}
  • Warp大小32:一半线程等,一半执行,浪费50%执行周期
  • Warp大小1024:极端情况下1023个线程等1个线程,浪费99.9%执行周期

Warp越大,分支发散的惩罚越重,并行效率越低。


3. 同步开销#

Warp内所有线程共享指令流,但Warp之间需要显式同步。Warp越大:

  • 同步屏障涉及线程越多,等待最慢线程的时间越长
  • 共享内存竞争概率增加

4. 硬件复杂度和时钟频率#

  • 32路并行:控制逻辑相对简单,布线短,时钟频率可以做高
  • 1024路并行:需要巨大的指令广播网络和结果收集网络,面积、功耗、延迟都会爆炸,时钟频率被迫降低

GPU追求高吞吐量,靠的是大量小单元高频运行,而不是少量大单元低频运行。


5. 内存访问合并(Coalescing)#

Warp内线程的内存访问模式被硬件优化为合并成一次事务。32个线程的地址通常容易对齐和合并;1024个线程的地址范围太大,合并效率反而下降,内存带宽利用率降低。


为什么是32而不是其他数字?#

因素32的优势
二进制幂次32 = 2⁵,地址计算、掩码操作硬件实现简单
与缓存行匹配典型缓存行64~128字节,32个float/int刚好对齐
历史演进NVIDIA从早期架构沿用至今,软件生态已固化
经验验证实际 workload 测试表明32在延迟隐藏和发散容忍间取得较好平衡

SM | Warp | Thread#

Warp是硬件执行的原子单位,32是在寄存器开销、延迟隐藏能力、分支发散代价、硬件复杂度、内存合并效率之间权衡后的工程最优解,不是越大越好。

描述含义
”一个线程块只能在一个SM上被调度”线程块是不可拆分的——一个Block的所有线程必须在同一个SM上执行,不能把一个Block拆到两个SM上
”一旦调度,保存在该SM上直到执行完成”线程块是不可迁移的——执行期间不会从SM A换到SM B
”一个SM可以容纳多个线程块”一个SM的资源足够时,可以同时驻留多个Block
概念说明
Block ↔ SM多对一(多个Block可以映射到同一个SM)
Block ↔ Block一个Block不能拆到多个SM(一对一绑定)

块内用__syncthreads()同步,块间靠内核拆分同步;Warp等待时不空转,SM立刻切到其他Warp执行,且切换不花代价,因为所有上下文早已静态分配在SM上。

两种 NVIDIA GPU 架构#

Fermi#

组件规格作用
CUDA核心总数512个整数ALU + 浮点FPU,每个周期执行一条整数或浮点指令
SM数量16个独立调度和执行单元,每个SM管理自己的Warp和资源
每SM CUDA核心32个单SM内的并行执行宽度
每SM Warp调度器2个双发射,每个周期可选两个就绪Warp发射指令
每SM LD/ST单元16个加载/存储操作,处理内存读写
每SM SFU4个特殊函数单元(sin/cos、倒数、开方等)
寄存器文件32768 × 32位所有活跃线程的寄存器存储
共享内存/L1缓存64KB(可配置)Block内线程共享数据,或与L1缓存动态划分
全局内存接口6 × 384-bit GDDR5总位宽2304-bit,高带宽访问显存
全局显存容量最高6GB存储大规模数据集
主机接口PCIe总线CPU与GPU之间的数据传输通道
GigaThread引擎全局调度器将线程块分配到各SM的Warp调度器

Kepler#

特性FermiKepler
制程40nm28nm
SM名称SMSMX(下一代SM)
每SM/SMX CUDA核心32个192个
每SM/SMX Warp调度器2个(双发射)4个
每SM/SMX LD/ST单元16个32个
每SM/SMX SFU4个32个
寄存器文件32768 × 32位65536 × 32位
共享内存/L164KB64KB(不变)
新增动态并行Hyper-QGPU Boost
CUDA 执行模型
https://www.dongyanzhang.com/posts/cuda-c/cuda-c-003/
作者
阿东阿言
发布于
2026-07-18
许可协议
CC BY-NC-SA 4.0