第二章:GPU架构基础——GPU与CPU的架构差异、NVIDIA GPU架构演进、CUDA核心与SM概念
各位同学,大家好。今天我们聊聊GPU架构。说实话,很多初学者一上来就写CUDA代码,结果性能惨不忍睹。为什么?因为你不懂硬件在想什么。我当年也是这样,写了个并行归约,跑起来比CPU还慢……后来一查,全局内存访问没对齐,bank conflict一大堆。嗯,从那以后我养成了一个习惯:写代码前,先画架构图。
2.1 GPU与CPU的架构差异
CPU和GPU,说白了就是两种完全不同的设计哲学。CPU是「全能选手」,什么活都能干,但一次只能干几件。GPU是「专业打手」,只会干一件事——并行计算,但一次能干成千上万件。
我给大家打个比方。CPU就像一个大厨,一个人能切菜、炒菜、摆盘,样样精通。GPU就像一百个帮厨,每个人只会切土豆丝,但一百个人一起切,速度飞快。你想想看,如果你要做一万盘酸辣土豆丝,谁更快?
具体到硬件层面,差异主要体现在这几个方面:
| 对比维度 | CPU | GPU |
|---|---|---|
| 设计目标 | 低延迟、单线程性能 | 高吞吐、大规模并行 |
| 核心数量 | 4-16个(桌面级) | 数千个(如A100有6912个CUDA核心) |
| 缓存策略 | 大容量L1/L2/L3缓存 | 小缓存,依赖高带宽显存 |
| 控制单元 | 复杂分支预测、乱序执行 | 简单控制,SIMT模式 |
| 内存带宽 | ~50 GB/s(DDR5) | ~2 TB/s(HBM2e/3) |
| 适用场景 | 操作系统、串行任务 | 矩阵运算、图像处理、AI训练 |
这里有个关键点:GPU的「核心」和CPU的「核心」不是一回事。CPU核心是完整的计算单元,有独立的ALU、控制单元、缓存。GPU的CUDA核心本质上只是一个浮点运算单元(FP32 ALU),它必须依赖SM(流多处理器)中的调度器和共享资源才能工作。这一点我后面会细讲。
核心差异总结: CPU用大量晶体管做控制和缓存,为了加速单线程;GPU用大量晶体管做计算单元,为了加速并行任务。两者没有谁优谁劣,只有谁更合适。
2.2 NVIDIA GPU架构演进
NVIDIA的GPU架构,从Fermi到Ampere,我基本都经历过。说实话,每次架构迭代都像一次「进化」,而不是「革命」。但有几个关键节点,值得大家记住。
2.2.1 Fermi架构(2010年)
Fermi是第一个真正为通用计算设计的GPU架构。我记得当时拿到GTX 480,第一感觉是「这玩意儿真热」,但性能确实炸裂。Fermi引入了几个关键特性:
- SM(流多处理器)概念正式确立:每个SM包含32个CUDA核心
- 可配置的共享内存和L1缓存:48KB共享内存 + 16KB L1,或者反过来
- 真正的ECC支持:对科学计算来说,这是刚需
- 双精度性能大幅提升:每个SM有16个双精度单元
Fermi的SM设计,说白了就是奠定了现代GPU计算的基础。虽然现在看32个核心一个SM有点少,但在当时已经是革命性的了。
2.2.2 Kepler架构(2012年)
Kepler是Fermi的「优化版」。我个人觉得Kepler最大的贡献是引入了SMX——每个SMX有192个CUDA核心。你没看错,从32直接跳到192。为什么能翻这么多倍?因为Kepler把调度逻辑简化了,让更多晶体管用在计算上。
Kepler还有一个重要特性:Hyper-Q。它允许CPU同时向GPU提交32个任务队列(之前只有1个)。我在项目中遇到过一个问题:CPU提交任务的速度跟不上GPU执行的速度,导致GPU空闲。用了Hyper-Q之后,这个问题基本解决了。
避坑指南: 我曾经在Kepler上调试一个程序,发现性能始终上不去。后来发现是全局内存访问没有合并(coalesced)。Kepler对内存访问模式非常敏感,一个warp(32个线程)如果访问不连续的内存地址,性能会暴跌。记住:让相邻线程访问相邻地址。
2.2.3 Turing架构(2018年)
Turing架构,大家应该比较熟悉。它引入了RT Core(光线追踪核心)和Tensor Core(张量核心)。但对我们做异构计算的人来说,Turing最重要的变化是SM架构重构。
Turing的SM包含64个CUDA核心、8个Tensor Core、1个RT Core。它把SM分成了4个处理块(processing block),每个块有16个CUDA核心。这种设计让调度更灵活,也提高了资源利用率。
另外,Turing引入了独立线程调度(Independent Thread Scheduling)。之前的架构中,一个warp里的线程必须执行同一条指令(SIMT模式)。Turing允许线程独立执行,这对处理分支发散(divergent branching)非常有帮助。
2.2.4 Ampere架构(2020年)
Ampere是目前最主流的架构(A100、RTX 30系列)。它把SM进一步升级,每个SM包含128个CUDA核心。A100有108个SM,总共13824个CUDA核心。嗯,这个数字确实吓人。
Ampere的几个关键改进:
- 第三代Tensor Core:支持稀疏矩阵计算,性能翻倍
- MIG(多实例GPU):一个物理GPU可以切分成7个独立实例,每个实例有自己的显存和缓存
- NVLink 3.0:GPU间通信带宽提升到600 GB/s
- L2缓存增大到40MB:A100的L2缓存比V100大了7倍
我个人觉得Ampere最大的亮点是MIG。以前做多租户GPU集群,一个任务占不满GPU,但又不能和其他任务共享,资源浪费严重。MIG解决了这个问题,一个A100可以同时跑7个不同的任务,互不干扰。
2.3 CUDA核心与SM(流多处理器)概念
好,现在我们来聊聊最核心的概念:CUDA核心和SM。很多初学者把CUDA核心等同于CPU核心,这是个大误区。
2.3.1 什么是CUDA核心?
CUDA核心,说白了就是一个浮点运算单元(FP32 ALU)。它只能做一件事:计算。它没有控制单元,没有缓存,没有寄存器。它必须依赖SM来获取指令和数据。
一个SM包含多个CUDA核心。比如Ampere架构的SM有128个CUDA核心。这些核心共享SM内部的调度器、寄存器文件、共享内存和L1缓存。
为什么叫「CUDA核心」?因为NVIDIA的并行计算平台叫CUDA。本质上,CUDA核心就是为CUDA程序服务的硬件执行单元。
2.3.2 什么是SM(流多处理器)?
SM才是GPU真正的「计算核心」。它包含了:
- CUDA核心:执行浮点和整数运算
- Warp调度器:负责调度warp(32个线程为一组)
- 寄存器文件:每个SM有大量的寄存器(如A100每个SM有65536个32位寄存器)
- 共享内存:SM内部的高速存储,容量通常为48KB-164KB
- L1缓存:和共享内存共用,可配置
- Tensor Core(如果有):专门做矩阵乘法的硬件
- 特殊函数单元(SFU):处理sin、cos、sqrt等复杂运算
一个GPU有多个SM。比如A100有108个SM,每个SM有128个CUDA核心,总共13824个CUDA核心。
重要概念: 线程块(Thread Block)是映射到SM上执行的。一个SM可以同时运行多个线程块,但线程块内的线程只能在一个SM内通信(通过共享内存)。这就是为什么共享内存的访问延迟远低于全局内存。
2.3.3 Warp:GPU调度的基本单位
这里要引入一个关键概念:Warp。Warp是32个线程组成的组,是GPU调度和执行的基本单位。SM中的warp调度器每次选择一个warp,然后让这个warp里的32个线程执行同一条指令。
为什么会这样?因为GPU的设计哲学是「单指令多线程」(SIMT)。32个线程执行同一条指令,但操作不同的数据。这就像32个人同时做同一道菜,但每个人用的食材不同。
如果warp里的线程出现了分支(if-else),会发生什么?嗯,这就是所谓的分支发散。GPU会执行所有分支路径,但只保留对应线程的结果。比如warp里16个线程走if,16个线程走else,GPU会先执行if路径(16个线程工作,16个线程空闲),再执行else路径(16个线程工作,16个线程空闲)。性能直接减半。
警告: 分支发散是GPU性能杀手。我曾经在一个项目中,因为一个简单的if-else语句,性能从80%利用率掉到了30%。后来我把数据重新组织,让同一个warp里的线程走同一个分支,性能立刻恢复。记住:尽量让warp内的线程执行相同的指令流。
2.3.4 从线程到SM的映射关系
我们写CUDA程序时,会定义grid(网格)和block(线程块)。GPU硬件会把这些逻辑概念映射到物理硬件上:
- Grid → 整个GPU(所有SM)
- Block(线程块) → 单个SM
- Warp(32个线程) → SM中的warp调度器
- Thread(线程) → CUDA核心
举个例子:假设你启动了一个grid,包含16个block,每个block有256个线程。GPU有8个SM。那么每个SM会分配到2个block(16/8=2)。每个block的256个线程会被分成8个warp(256/32=8)。SM中的warp调度器会轮流执行这8个warp。
这里有个关键点:一个SM能同时运行的warp数量是有限的。比如A100的每个SM有4个warp调度器,每个调度器可以同时管理多个warp。但实际能同时执行的warp数量取决于资源(寄存器、共享内存)是否充足。
2.4 本章知识体系图
下面我用一张SVG图来总结本章的核心逻辑。这张图展示了从CPU/GPU架构差异,到NVIDIA架构演进,再到CUDA核心与SM概念的完整知识链条。
2.5 小结
这一章我们聊了三个核心问题:
- CPU和GPU为什么不一样? 设计目标不同,导致硬件结构天差地别。CPU追求低延迟,GPU追求高吞吐。
- NVIDIA架构是怎么演进的? 从Fermi到Ampere,每个架构都在增加核心数量、优化调度效率、引入专用硬件(Tensor Core、RT Core)。
- CUDA核心和SM到底是什么? CUDA核心是运算单元,SM是完整的计算引擎。Warp是调度的基本单位,分支发散是性能杀手。
我个人觉得,理解GPU架构最好的方法就是「动手」。写一个简单的向量加法,然后用NVIDIA Nsight Compute分析一下,看看你的kernel到底用了多少SM、多少寄存器、多少共享内存。你会发现,原来代码跑得慢,不是GPU不行,是你没用好。
一个小建议: 刚开始学CUDA时,不要追求代码的「优雅」。先写能跑的程序,然后用profiler分析,再优化。我见过太多人花一周时间写了一个「完美」的kernel,结果一跑,性能还不如CPU。嗯,先跑起来,再优化,这是铁律。
公众号:蓝海资料掘金营,微信deep3321