1、GPU架构概述:GPU发展简史、GPU vs CPU核心差异、现代GPU通用架构
各位同学好,我是老张。今天咱们开始这门课的第一讲。说实话,每次讲GPU架构我都挺感慨的——从当年做图形加速的小芯片,到现在撑起AI半壁江山的算力核心,这发展速度真是让人跟不上。嗯,咱们先捋一捋它的发展脉络。
1.1 GPU发展简史:从图形卡到通用计算引擎
GPU的历史,说白了就是一部「从专用走向通用」的进化史。
- 1990年代:固定功能管线时代
那时候的GPU叫「图形加速卡」,只能干固定的事——画三角形、贴纹理、做光栅化。我记得刚入行时调过一块S3 Virge的板子,为了让它正确显示一个旋转的茶壶,折腾了整整一周。你想想看,那时候的GPU连可编程都谈不上,更别提通用计算了。 - 2001-2006年:可编程着色器出现
NVIDIA的GeForce 3引入了顶点着色器和像素着色器。这是个转折点——程序员终于能写点自己的代码跑在GPU上了。不过那时候的编程模型还很别扭,你得用图形API(比如DirectX)去「伪装」通用计算。我在项目中试过用像素着色器做矩阵乘法,那代码写得...嗯,现在回头看简直是行为艺术。 - 2007年至今:统一架构与通用计算爆发
NVIDIA的G80架构(GeForce 8800 GTX)是个里程碑。它把顶点着色器和像素着色器合并成了统一的流处理器(CUDA Core),并且推出了CUDA编程模型。从此GPU不再是「图形卡」,而是真正的「通用并行处理器」。我2010年参与过一个气象模拟项目,用CUDA把计算时间从3天缩短到4小时——那种震撼感,到现在都记得。
关键转折点: 2007年CUDA的发布,让GPU从「图形加速器」变成了「通用并行计算平台」。没有这一步,今天的AI浪潮根本不可能发生。
1.2 GPU vs CPU核心差异:为什么GPU能跑这么快?
很多人问我:「老张,GPU和CPU到底差在哪?为什么CPU不能像GPU那样并行?」
这个问题,咱们从三个维度来看:
| 维度 | CPU | GPU |
|---|---|---|
| 设计目标 | 低延迟、串行执行、复杂控制 | 高吞吐、并行执行、简单控制 |
| 核心特点 | 大缓存、强分支预测、乱序执行 | 大量ALU、小缓存、SIMT执行模型 |
| 典型面积分配 | 控制逻辑占40%,缓存占40%,ALU占20% | 控制逻辑占10%,缓存占10%,ALU占80% |
| 适用场景 | 操作系统、数据库、交互应用 | 矩阵运算、图像处理、深度学习 |
为什么会这样?
CPU的设计哲学是「把一件事做到最快」。它花大量晶体管在分支预测、乱序执行、大容量缓存上——就是为了让单线程跑得飞快。你想想看,操作系统调度、数据库查询、Web服务器响应,这些任务本质上都是串行的,而且充满了分支和依赖。
GPU的设计哲学是「同时做一万件简单的事」。它把绝大部分晶体管都给了ALU(算术逻辑单元),控制逻辑和缓存能省则省。每个CUDA Core都很「笨」——它不会乱序执行,不会做复杂的分支预测,但它有几千个这样的「笨核心」同时干活。
我的经验: 判断一个任务适不适合GPU,就看它能不能被拆成大量独立的小任务。如果任务之间有大量数据依赖或分支,那CPU反而更快。我曾经见过有人硬要把链表遍历放到GPU上跑,结果比CPU还慢10倍——这就是典型的「用错工具」。
1.3 现代GPU通用架构:SM/CU、内存层次、互联总线
好,咱们来看看现代GPU到底长什么样。以NVIDIA的架构为例(AMD的类似,只是叫法不同):
1.3.1 SM/CU:计算的基本单元
SM(Streaming Multiprocessor,流式多处理器)是GPU的核心计算单元。一个GPU芯片里有几十到上百个SM。
每个SM内部包含:
- CUDA Core(核心):执行整数和浮点运算。一个SM通常有64-128个。
- 共享内存(Shared Memory):SM内部的高速存储,容量小(几十KB到上百KB),但延迟极低。
- 寄存器文件(Register File):每个线程的私有存储,容量有限(每个线程最多255个寄存器)。
- Warp调度器:负责把32个线程组成一个Warp,并调度执行。
这里有个关键概念——SIMT(单指令多线程)。说白了就是:32个线程(一个Warp)执行同一条指令,但操作不同的数据。这和CPU的SIMD(比如AVX指令)有点像,但更灵活——每个线程可以有自己的寄存器、自己的地址计算。
避坑指南: 我曾经在项目中遇到过一个性能问题——某个kernel的occupancy(占用率)只有25%。查了半天才发现,是因为每个线程用了太多寄存器,导致SM能同时容纳的线程数大幅减少。记住:寄存器是稀缺资源,别滥用。
1.3.2 内存层次结构:速度与容量的博弈
GPU的内存层次和CPU类似,但更「极端」:
| 层级 | 容量 | 带宽 | 延迟 | 作用域 |
|---|---|---|---|---|
| 寄存器 | 每个线程最多255个 | 极高 | 1个周期 | 线程私有 |
| 共享内存 | 每个SM 48-96KB | 极高 | ~20个周期 | Block内共享 |
| L1缓存 | 每个SM 128-256KB | 高 | ~30个周期 | SM私有 |
| L2缓存 | 整个芯片 4-40MB | 中等 | ~200个周期 | 芯片共享 |
| 全局内存(HBM/GDDR) | 16-80GB | 1-2TB/s | ~400-800个周期 | 所有线程 |
嗯,这里要注意:全局内存的带宽虽然高(HBM2e能到2TB/s),但延迟也高得吓人。所以优化的核心思路就是——尽量把数据往上层搬。
我个人的习惯是:先看数据能不能放共享内存,再看能不能用寄存器。实在不行才去访问全局内存。而且访问全局内存时,一定要保证合并访问(Coalesced Access)——也就是相邻的线程访问相邻的地址。否则带宽利用率会惨不忍睹。
1.3.3 互联总线:把芯片串起来
现代GPU不是单打独斗的。一个GPU芯片内部有多个GPC(图形处理簇),每个GPC包含多个SM。它们之间通过片上互联(比如NVIDIA的NVLink或AMD的Infinity Fabric)连接。
多GPU之间呢?
- PCIe总线:最通用的互联方式,但带宽有限(PCIe 4.0 x16约32GB/s)。
- NVLink:NVIDIA的高速互联,带宽可达PCIe的5-10倍。我去年调过一个8卡DGX系统,NVLink的带宽确实给力——但编程复杂度也上去了。
- Infinity Fabric:AMD的方案,类似NVLink,但更开放。
性能建模的关键: 在做GPU性能建模时,千万别只盯着计算单元。很多时候瓶颈在内存带宽或互联总线上。我见过太多人把kernel优化到极致,结果发现数据搬运的时间比计算还长——这就是典型的「木桶效应」。
小结
这一章咱们聊了GPU的来龙去脉、和CPU的本质区别、以及现代GPU的三大核心组件:SM/CU、内存层次、互联总线。
下一章咱们会深入SM内部,看看Warp调度、指令发射、以及那些让GPU「又爱又恨」的分支发散问题。嗯,到时候我会分享一个我踩过的坑——一个看似简单的if-else语句,让性能掉了60%。
今天就到这儿。有问题随时问我。
公众号:蓝海资料掘金营,微信deep3321