Roofline:先判断瓶颈,再谈优化

Lesson 01 · CUDA 性能调优 · 建立核心心智模型

调优一个慢 kernel 时,新手最常犯的错误是:凭直觉乱优化。 加 shared memory、调 block 大小、展开循环……结果性能纹丝不动。 原因是:每个 kernel 都被某一种资源卡住,而你优化了另一种资源。 本节你将掌握调优的第一性原理——先判断瓶颈类型,再动手

本节目标(一个可带走的胜利): 给定一个 kernel 的「算术强度」和你的 GPU 规格, 你能判断它是 访存瓶颈(memory-bound) 还是 计算瓶颈(compute-bound), 从而知道该往哪个方向优化

1. 两堵墙:每个 kernel 都撞其中一堵

一个 GPU kernel 要干两件事:搬数据(从显存读写)和 算数据(在 SM 上做浮点/整数运算)。 GPU 的这两种能力是分开的、各有上限:

关键洞察:这两件事同时进行、互相重叠。kernel 的实际耗时,取决于哪一件先做不完—— 那就是它的瓶颈。优化非瓶颈的那一边,总耗时不会变。

就像水管接水:水龙头流量(带宽)和水桶大小(算力)决定接满一桶水的时间。 如果水龙头细,你换个更大的桶毫无意义——你是「带宽瓶颈」。

2. 算术强度:决定瓶颈的那个比值

怎么知道一个 kernel 撞哪堵墙?看它的 算术强度(Arithmetic Intensity, AI):

算术强度 = 总计算量 ÷ 总访存量 = FLOPs / Bytes
「每从显存搬 1 个字节,我能做多少次浮点运算?」

这个比值是 kernel 自身的算法属性,和 GPU 无关。举两个 AI 里的典型例子:

算子特征算术强度
逐元素加法 c = a + b读 8 字节,算 1 次极低(≈0.125)
大矩阵乘 GEMM每个元素被复用 N 次高(可达几十~上百)

这解释了一个 AI 工程师天天遇到的现象:逐元素算子、归一化、softmax 几乎总是访存瓶颈, 而大矩阵乘才有机会成为计算瓶颈。[1]

3. Roofline 图:把两堵墙画出来

把算术强度放横轴、可达性能放纵轴,就得到 Roofline 图——一张能一眼看出瓶颈的图:

性能 (FLOP/s)
  ▲
峰值算力 ┤        ___________________  ← 计算屋顶(水平线)
        │       /
        │      /  ← 访存屋顶(斜线,斜率=带宽)
        │     /
        │    /        memory-bound │ compute-bound
        │   /                      │
        │  /                       │
        └─┴──────────────────────────────────▶ 算术强度 (FLOP/Byte)
                    ↑ ridge point(脊点)
判断法则:把 kernel 的算术强度和脊点比较——
AI < 脊点 → 访存瓶颈(在斜线下方,优化访存)
AI > 脊点 → 计算瓶颈(在水平线下方,优化计算)

现代数据中心卡的脊点高得吓人。例如 A100:峰值 FP32 约 19.5 TFLOP/s,带宽约 1.5 TB/s, 脊点 ≈ 13 FLOP/Byte。[1] 这意味着绝大多数 AI 算子都落在斜线左侧——访存瓶颈。 这就是为什么「访存优化」是 CUDA 调优的重头戏。

4. 练习:判断瓶颈(动手回忆)

下面 4 道题不要看上文,凭记忆判断。点选项立刻看反馈。 假设 GPU 脊点 = 13 FLOP/Byte。

💬 卡住了就问我。 我是你的老师——算术强度怎么手算?你的卡脊点是多少? 某个 AI 算子到底算哪类?随时追问,把不清楚的地方挖透。

5. 动手:在你自己的卡上验证(可选)

你有数据中心卡,强烈建议做这一步,把抽象变具体。用 Nsight Compute 跑任意一个 kernel:

# 编译你的程序后,用 ncu 抓 Speed of Light 段
ncu --section SpeedOfLight ./your_program

# 报告里看这两行:
#   Compute (SM) Throughput  →  计算利用率
#   Memory Throughput        →  访存利用率
# 哪个接近 100%,就是哪个瓶颈。

Nsight Compute 的 Speed of Light 段其实就是 roofline 的自动化版本:它直接告诉你 kernel 贴着哪堵墙。[2] 下一节我们会专门拆解怎么读这份报告。

主源推荐(本节精读 / 必看)

📘 CUDA C++ Best Practices Guide ——调优的权威圣经。本节相关的是开头的「Assess(评估)」与「Memory Optimizations」章节, 核心思想就是:先测量定位瓶颈,再优化。这是你接下来反复回看的第一资源。