GPU架构基础:核心组成、流多处理器(SM)、线程束(Warp)、内存层次结构、GPU计算能力

好,咱们进入第二讲。这一讲我打算把GPU的“骨架”给你拆开看看。说白了,你得知道手里这把“异构计算”的刀,到底长什么样、怎么磨的。

很多初学者一上来就学CUDA编程,结果写出来的代码跑得比CPU还慢。为什么?因为根本不了解GPU的脾气。我当年就吃过这个亏,一个简单的向量加法,优化了一周,性能纹丝不动。后来才发现,是我对SM和Warp的理解太肤浅了。

GPU核心组成:一个“大管家”和一群“打工人”

先看整体。一个GPU芯片,你可以把它想象成一个超级工厂。

  • 全局调度器(GigaThread Engine):这是大管家。它负责把任务(线程块)分配给下面的各个车间。
  • 流多处理器(SM):这是车间。每个车间里有一堆工人(CUDA核心)和共享的工具箱(共享内存)。
  • 内存控制器:这是仓库管理员。负责从显存(全局内存)里搬货。

我个人习惯把GPU看作一个“延迟隐藏机器”。它不是为了把单次计算做快,而是为了同时处理海量任务,让计算单元永远不闲着。

流多处理器(SM):GPU的心脏

SM是GPU里最重要的计算单元。一个GPU里有多少个SM,基本决定了它的算力上限。

每个SM内部包含:

  • CUDA核心:执行整数和浮点运算的单元。注意,它们不是独立的CPU,而是高度流水线化的执行单元。
  • 共享内存(Shared Memory):SM内部的高速缓存,由程序员手动管理。速度极快,但容量很小(通常几十KB到上百KB)。
  • 寄存器文件(Register File):每个线程私有的“草稿纸”。容量有限,如果每个线程用太多寄存器,会限制SM上同时运行的线程数。
  • Warp调度器:负责从就绪的Warp中挑选一个,发射指令到CUDA核心。
  • 加载/存储单元(LD/ST):处理内存访问请求。
  • 特殊函数单元(SFU):处理sin、cos、sqrt等复杂数学运算。

关键点:SM是独立的。每个SM有自己的寄存器、共享内存和调度器。线程块一旦被分配给某个SM,就会一直待在那里,直到执行完毕。这叫“驻留”。

我在项目中遇到过一个问题:一个kernel里用了太多共享内存,结果每个SM只能同时运行一个线程块。SM的利用率直接掉到谷底。嗯,这就是典型的“资源限制”案例。

线程束(Warp):GPU执行的最小单位

这是GPU架构里最反直觉、也最重要的概念。

你写代码时,觉得是32个线程在并行执行。但在硬件眼里,这32个线程被捆绑成一个Warp,一起取指令、一起执行。

Warp是怎么工作的?

  • 一个Warp包含32个线程。这32个线程共享同一个程序计数器(PC)。
  • Warp调度器每次发射一条指令,Warp里的所有线程都执行这条指令。
  • 如果线程们走的分支不同(比如if-else),就会发生“Warp发散”。

避坑指南:我曾经写过一个kernel,里面有个if语句,一半线程走true分支,一半走false分支。结果性能直接腰斩。因为Warp必须串行执行两个分支,先执行true的16个线程,再执行false的16个线程。你想想看,这等于浪费了一半的算力。

所以,写GPU代码时,要尽量保证同一个Warp里的线程走相同的分支。说白了,就是让它们“步调一致”。

内存层次结构:速度与容量的博弈

GPU的内存系统,是一个典型的金字塔结构。越往上,速度越快,容量越小。

内存类型 位置 速度 容量 作用域
寄存器 SM内部 最快(1个周期) 非常小(每个线程几十个) 线程私有
共享内存 SM内部 快(几个周期) 小(几十KB) 线程块内共享
L1缓存 SM内部 较快 几十KB SM内所有线程
L2缓存 芯片上 中等 几MB 所有SM共享
全局内存(显存) 芯片外 慢(几百个周期) 大(几GB到几十GB) 所有线程
本地内存 芯片外(显存) 由编译器决定 线程私有(寄存器溢出时使用)

这里有个常见的误解:很多人以为L1缓存和共享内存是独立的。其实在NVIDIA的架构里,它们共享同一块物理SRAM。你可以通过编译器指令来分配比例。比如,你可以配置48KB共享内存+16KB L1,或者反过来。

我的经验:如果kernel里需要频繁的线程间通信,我会把更多的SRAM分配给共享内存。如果只是数据复用,我会倾向于多给L1缓存。这个取舍,得根据具体算法来定。

GPU计算能力:一张“能力清单”

NVIDIA用“计算能力”(Compute Capability)来标识GPU的硬件特性。比如,RTX 3090的计算能力是8.6,A100是8.0。

这个数字很重要。它决定了:

  • 每个SM最多能驻留多少个Warp
  • 每个线程块最多能有多少个线程
  • 共享内存的最大容量
  • 是否支持某些特殊指令(比如Tensor Core)

举个例子,计算能力7.0(V100)的GPU,每个SM最多能驻留64个Warp(2048个线程)。而计算能力8.0(A100)的GPU,这个数字变成了64个Warp,但每个Warp的调度效率更高。

我建议你在写代码前,先查一下目标GPU的计算能力。NVIDIA官方文档里有个表格,列出了所有计算能力对应的硬件参数。这个表格,我几乎每做一个新项目都要翻一遍。

一句话总结:GPU架构的核心,就是SM、Warp和内存层次结构这三板斧。理解了它们,你就理解了GPU为什么能并行、为什么会有性能瓶颈、以及该怎么优化。

下一讲,我们会深入Warp的调度机制,聊聊“延迟隐藏”到底是怎么实现的。到时候,你会对GPU的“并发”能力有更直观的认识。