GPU 解剖与 LLM Token 数据流
要理解 LLM 推理为什么慢、瓶颈在哪,必须先看清一个 token 在 GPU 硬件里走过的完整路径。本文从 H100 芯片全貌、SM 内部结构、内存层级,一直讲到一个 token 从输入到输出的数据流动,配有可交互图示。
Part 1: GPU 芯片全貌
H100 SXM 是 814mm² 的巨型芯片,包含 132 个 SM、80GB HBM3、3.35 TB/s 带宽。下面是一张可交互的 GPU die 示意图,点击任意组件(HBM、Memory Controller、L2 Cache、Crossbar、SM、NVLink)查看详细说明:
Part 2: SM(流处理器)内部
每个 SM 是 GPU 的基本计算单元,里面包含 Tensor Cores、CUDA Cores、SRAM 和调度器。
Warp Scheduler × 4
每个 SM 有 4 个 Warp 调度器,每个管理多个 Warp(32 线程为一组)。当一个 Warp 等待内存时,调度器立刻切换到另一个就绪的 Warp(延迟隐藏)。每 SM 最多同时管理 64 个 Warp = 2048 个线程。
Tensor Cores × 4 (4th Gen)
专为矩阵乘法设计的硬件单元。每个 Tensor Core 每周期可算一个 4×4 矩阵 FMA,支持 FP16、BF16、FP8、INT8 格式。**LLM 中几乎所有 Linear 层都在这里算。**输入从 Register File 读取,结果写回 Register。
CUDA Cores (FP32) × 128
通用浮点运算单元(ALU)。处理逐元素操作:加法、RMSNorm、GeLU/SiLU 激活、softmax、RoPE 位置编码等。每周期 1 个 FP32 FMA / core。比 Tensor Core 灵活但慢得多(做矩阵乘法效率极低)。
Shared Memory / L1 (SRAM) — 228KB
SM 内的高速暂存区,程序员可显式管理。Flash Attention 的核心:把 K、V 分块加载到这里,在 SRAM 中完成
Register File — 256KB
每个线程的私有超高速存储。Tensor Core 和 CUDA Core 直接从这里读/写操作数。延迟 ~1 cycle,带宽 ~60 TB/s。每线程最多 255 个 32-bit 寄存器。寄存器压力:用太多 → 能同时跑的 Warp 数变少 → 延迟隐藏效果变差。
Load/Store Units × 32
负责所有内存读写操作。每次 memory request 经过:(1) 先查 L1/Shared Memory;(2) Miss → 查 L2 Cache;(3) Miss → 去 HBM。32 个 LD/ST unit 意味着每周期可发起 32 个 memory transaction。LLM decode 时,大部分时间都在等这些 unit 把权重从 HBM 搬进来。
三个关键直觉
Tensor Core vs CUDA Core:Tensor Core 专做 D = A×B + C 的矩阵 FMA,一拍算 4×4 矩阵;CUDA Core 一拍算 1 个标量乘加。做一个 4×4 矩阵乘法,Tensor Core 1 个周期,CUDA Cores 需要 64 次乘 + 48 次加。所以 LLM 的 Linear 层全用 Tensor Core,逐元素操作用 CUDA Core。
为什么 SRAM 这么重要:HBM 是 80GB 但只有 3.35TB/s;SRAM 每 SM 只有 228KB 但有 ~30TB/s。Flash Attention 的秘密就是把数据尽量留在 SRAM 中计算,避免来回读写 HBM。朴素 Attention 把
Warp 和延迟隐藏:HBM 读取延迟 ~400ns ≈ 数百个时钟周期。如果只有 1 个线程组在跑,GPU 大部分时间在等内存。解决办法是每 SM 放 64 个 Warp,当一个 Warp 等内存时调度器瞬间切换到另一个就绪的 Warp。这就是 GPU 的核心设计哲学 —— 用并发换延迟。
Part 3: 内存层级
从最远的 HBM 到最近的 Register,越近越快但越小:
| 层级 | 容量 | 带宽 | 延迟 | 存放内容 |
|---|---|---|---|---|
| HBM3(显存) | 80 GB | 3.35 TB/s | ~400 ns | 模型权重 + KV Cache + 激活值 + 优化器状态 |
| L2 Cache | 50 MB | ~12 TB/s | ~150 ns | 所有 SM 共享,缓存 RoPE 表、小权重、频繁访问的 KV |
| Shared Memory / L1 (SRAM) | 228 KB / SM | ~30 TB/s | ~30 ns | SM 私有,程序员管理,Flash Attention 工作区 |
| Register File | 256 KB / SM | ~60 TB/s | ~1 ns | 线程私有,计算单元直接操作数来源 |
| Tensor + CUDA Cores | 989 TFLOPS FP16 / ~67 TFLOPS FP32 | — | — | 从 Register 读操作数 → 计算 → 写回 Register |
**关键矛盾:**Tensor Cores 需要 989 TFLOPS 的「喂数据」速度,但 HBM 只能提供 3.35 TB/s。
这就是 H100 的算力带宽比(屋脊线)。LLM Decode 的 GEMV 只有 ~1-2 FLOPs/Byte —— Tensor Cores 99% 的时间在空等 HBM!
Part 4: Token 数据流动
下面这个可交互图示,逐步演示一个 token 从输入到输出在 GPU 硬件中的完整旅程(LLaMA-70B Decode)。每一步会高亮活跃的 HBM 区域、SM 和缓存,并说明数据从哪里来、到哪里去、经过什么计算单元:
整个流程的关键观察:
- **Step 2 / 5 / 8 / 10(各种 Projection)**都是 GEMV:权重远大于激活值,从 HBM 流式读取权重 → Tensor Cores 计算,是 memory-bound 的根源。
- **Step 4(Attention / Flash Decoding)**全程 score 矩阵不写回 HBM,只读一次 KV、输出一个向量。
- **Step 7(FFN Gate + Up)**是整个推理过程中最大的一次权重读取:W_gate + W_up = 896MB。
一层的总权重读取约 1.86GB(Attention 512MB + FFN 1.34GB)。70B 模型 80 层,每生成一个 token 需要读 ~148GB 权重 + ~1.3GB KV Cache ≈ 150GB。理论耗时:
实际约 55-70ms(各种 overhead)。最终输出只是 1 个整数(next_token_id) —— 这就是你看到的「一个字一个字冒出来」。然后这个 token 重新进入 Step 0,开始下一轮 decode。
本文正文 markdown 渲染,2 个交互图示通过自定义 {% anim %} 标签以隔离 iframe 嵌入,源自 Arkive 教程。