Chapter 03 · GPU / CUDA / 显存 / 并行基础
到这一章,你开始真正接触“为什么系统会慢”的底层来源。目标不是把你训练成 CUDA 内核工程师,而是建立足够可靠的硬件直觉:什么时候是算力问题,什么时候是显存容量问题,什么时候是带宽或通信问题,什么时候只是调度方式没有把设备利用起来。
到这一章,你开始真正接触“为什么系统会慢”的底层来源。目标不是把你训练成 CUDA 内核工程师,而是建立足够可靠的硬件直觉:什么时候是算力问题,什么时候是显存容量问题,什么时候是带宽或通信问题,什么时候只是调度方式没有把设备利用起来。
大模型推理问题很容易被一句“GPU 不够强”糊弄过去。但工程上你必须继续追问:是权重装不下?是 KV Cache 占满显存?是带宽在搬数据时耗光了?还是算子和并行组织让设备闲着?这一章就是建立这种追问能力。
建立足够实用的硬件执行模型,而不是追求底层实现细节本身。
至少能把算力、显存容量、显存带宽、卡间通信这四类资源分开理解。
不要试图一次记住所有 GPU 术语,重点是抓住“资源类型”和“系统症状”的对应关系。
对推理系统来说,GPU 不是一个抽象的大黑盒,而是一组擅长大规模并行计算的执行单元。模型里的矩阵乘、注意力和归一化不会“自动快起来”,它们通常会被拆成很多 kernel 送到 GPU 上执行。你不需要马上理解每个硬件细节,但需要知道:系统最终是在安排大量小计算块怎样被并行组织起来。
因此,推理系统里的很多问题其实都能翻译成一个更底层的问题:这段工作是怎么被提交到设备上的?设备有没有足够多的并行工作可做?数据读写是不是成了瓶颈?这就是为什么 kernel、线程块、stream 这些词虽然底层,但对理解推理执行很有帮助。
很多工程师听到 CUDA 会下意识想到“写底层代码”。但从推理系统学习角度,你更应该把它理解成 GPU 程序的执行接口和组织方式。推理框架、编译器、运行时最终都要借助这类接口把工作交给 GPU 执行。
这意味着即使你不自己写 CUDA,也最好知道它存在于系统哪一层:它连接的是“引擎想执行什么”和“GPU 实际如何执行”。后面当你看到算子优化、图编译或者高性能内核时,都会发现它们本质上是在改进这层连接。
容量问题指的是:权重、激活、中间状态和 KV Cache 到底能不能放得下。带宽问题指的是:这些数据能不能足够快地被读写和搬运。你可能有一张显存足够大的卡,但如果带宽跟不上,推理依然会慢;也可能算力足够强,但权重和缓存装不下,系统根本起不来。
在 LLM 推理里,二者都极其重要。权重规模和高并发请求会持续吃显存容量;长上下文和缓存访问模式又会持续消耗带宽。所以你不能只盯着“多少 GB 显存”,也不能只盯着理论 FLOPS。
“装不下”先想容量;“装得下但不够快”先想带宽、访问模式和执行组织。
模型大到单卡放不下时,你就会开始看到 tensor parallel、pipeline parallel 等概念。直觉上,“多卡一起干”似乎一定更快,但现实是:切分模型会引入更多通信、同步和调度成本。如果工作负载组织得不好,多卡未必比单卡更优。
所以并行设计本身就是一个系统问题:你为了缓解哪种压力切分?切分后带来的通信和同步成本能否接受?这个问题会在后面的部署与框架比较里反复出现。
当你看到“模型启动失败”“并发一高就 OOM”“吞吐很低但 GPU 利用率也不高”“多卡扩展不线性”这些症状时,本质上是在看硬件资源与执行组织的映射。学完本章后,你不一定能立刻修复问题,但应该已经能把症状归因到更合理的方向。
单卡问题主要集中在显存、带宽和内核效率;到了多卡,你还要考虑切分方式和卡间通信;跨机之后,网络拓扑、容错和更高层的服务编排也会一起进入问题域。所以“能不能扩更多卡”从来不是一道单一算力题,而是复杂度不断上升的系统题。
对入门学习来说,最重要的是先建立这三个台阶的意识。你可以暂时不深入每种并行策略的细节,但要知道每跨一个台阶,新增的成本类型是什么。
显存容量和显存带宽是两种完全不同的限制,解决思路也不同。
很多时候设备不忙,是因为内存搬运、调度空洞或请求组织不足,而不是模型太轻。
当问题还停留在单卡的缓存管理、内核效率或负载组织阶段时,盲目加卡往往只会把问题搬到通信层。
这通常不是“模型本身太大”这么简单,而是活跃请求叠加后,KV Cache 和中间状态把剩余显存迅速吃完了。
如果切分带来的通信和同步成本接近新增算力收益,就会出现“卡更多了,但收益没线性增长”的现象。
这章最需要的是“资源约束能翻译成什么症状”的直觉。图里左列和右列按行一一对应。
先分清是哪类资源在限制系统,再决定后面该往容量、带宽、算子还是通信方向想。
左列是资源类型。
右列是更容易看到的现象。
| 资源 / 维度 | 它限制什么 | 推理系统常见症状 | 后续常见优化方向 |
|---|---|---|---|
| 算力 | 单位时间能完成多少计算 | 内核效率低、热点算子执行慢 | 算子优化、编译、融合内核 |
| 显存容量 | 模型、缓存、并发请求能否放下 | 加载失败、OOM、并发受限 | 量化、切分、缓存管理 |
| 显存带宽 | 数据能否足够快地被读取和写回 | 算力不低但推理仍慢 | 内存布局优化、减少搬运、IO-aware 内核 |
| 卡间通信 | 多卡之间同步和交换数据的代价 | 扩卡后收益变差、时延抖动 | 并行策略调整、通信压缩、拓扑优化 |
推理快慢很少只是“GPU 型号”问题,更常见的是资源类型和工作负载组织不匹配。
只知道模型参数量,不知道上下文长度、并发度和缓存策略,几乎无法判断真实硬件压力。
至少覆盖算力、显存容量、显存带宽、卡间通信四类。最低完成标准是:任意给你一个症状,你能先猜最可能是哪类资源在作祟。
例如显存大小、带宽、是否适合多卡扩展。最低完成标准是:你能结合推理负载解释这些参数为什么重要,而不是只抄表格。
至少提到切分、同步、通信这三个关键词。最低完成标准是:你不再把并行当作零成本扩展。
场景示例:长上下文聊天、高并发短问答、单机本地推理。最低完成标准是:你的判断里要同时出现负载特征和资源特征。
一张资源类型与系统症状映射表。
一张你自己整理的 GPU 参数解释卡。
一段关于并行成本的简要说明。
如果你能举出不同症状,说明资源观已经建立。
你的答案里至少应该出现缓存、带宽或数据搬运。
如果你只说“更复杂”而没提通信和同步,说明还不够具体。
如果可以,后面学习优化时就更不容易误判。
适合建立 GPU 执行模型、线程组织和内存层级的基础认知。
适合把“概念知道”推进到“怎样看性能问题”的工程视角。
适合用来感受“IO-aware”思路如何把注意力问题转成更贴近带宽和内存访问的优化问题。
适合后面沿着硬件优化路线继续读高性能推理框架的实现方式。
适合观察跨 CPU / GPU / 本地推理路线的工程权衡。
适合提前感受“硬件平台特性和推理框架能力是如何耦合在一起”的。
这会让你忽略带宽、缓存访问模式、算子实现和调度策略带来的巨大差异。
只要发生切分,就会伴随同步和通信,收益从来不是免费的。
你不必写内核,但必须知道问题大概率落在哪类资源上,否则优化阶段会一直漂在表面。
有了这层硬件直觉后,下一章会重新回到请求链路本身,解释 prefill、decode、sampling 和 KV Cache 在引擎里如何组成一个真实的状态机。这样你才能理解为什么缓存会成为后续调度与优化的核心。