CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

源自15位全网作者

07:46

上周刷B站和知乎,我发现一个很反常的现象:短短一周之内,四五个不同的作者像约好了一样,密集更新同一类内容——Nsight Compute(下称NCU)性能分析教程。

数据也支持这个判断。8月12日,noinfra 的《以GEMM为例,学会使用Nsight Compute》在B站和小红书同步上线,要把 Nsight Compute 的每个面板彻底算清楚哔哩哔哩小红书。这条视频播放量不到两千,收藏却有380,收藏率接近20%。同一作者的续作《内存分析详解:Request、Sector、Wavefront》上线两天又被收了30多次哔哩哔哩。知乎上 Leezhou 的CUDA系列写到第三篇,主题也正好是从向量加法切到NCU性能分析知乎。"弹幕教我写代码"的NCU系列每期稳定上百收藏哔哩哔哩

教程扎堆只有一个解释:大量学CUDA的人卡在了同一个地方。

入门教程会教你 thread、block、grid,教你写一个正确的向量加法和矩阵乘法。但没人教你下一步——你写的 kernel 只有理论峰值的零头,慢在哪?怎么查?网上的优化技巧文章倒是很多,共享内存、合并访存、双缓冲,每个都说得头头是道,但落到你自己的 kernel 上,第一个问题永远是:我这到底是缺计算还是缺带宽?

这篇就把这周社区里被反复验证的排查路线整理出来:3步定位瓶颈,外加4个让过来人栽了跟头的坑。适合已经能写出正确kernel、正在被性能折磨的中阶同学。

第一步:先搞清楚NCU是什么、不测什么

NCU 是 NVIDIA 官方的 kernel 级性能分析器,随 CUDA Toolkit 完整安装自带,命令行工具叫 `ncu`,图形界面叫 `ncu-ui`。从 CUDA 12 开始,老的 nvprof 已经退役,kernel 级分析的主力就是它。

CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

两个边界先划清楚,能少走弯路:

  • NCU 只测单个 kernel 内部,不测 kernel 启动开销、不测 H2D/D2H 拷贝、不测多 kernel 之间的空隙。端到端时间线是 Nsight Systems(nsys)的活。程序整体慢,先用 nsys 看时间线,确认瓶颈真在某个 kernel 里,再对它开 NCU。

  • Windows 用户不用纠结环境。有同学在评论区问是不是必须装 Linux——不用,NCU 在 Windows 上有原生版本可以直接装,WSL2 里也能用哔哩哔哩

最简命令就一行:

```
ncu ./your_app
```

这会跑一遍基于规则的默认分析。要看全量指标,用 `ncu --set full ./your_app`——注意 full 档要采集几百个计数器,kernel 会被反复重放很多轮,慢是正常的,后面会讲这个机制带来的坑。

第二步:看SOL面板,先给瓶颈定性

打开报告,第一个要看的是 GPU Speed Of Light(SOL) 面板,它就两根条:

  • Compute (SM) Throughput:计算单元忙到什么程度

  • Memory Throughput:存储子系统忙到什么程度

两根条的相对高度,直接决定你后面往哪个方向挖。知乎上 Leezhou 用向量加法做了个标准示范:跑出来 DRAM Throughput 82.95%,Memory Throughput 82.95%,而 Compute (SM) Throughput 只有 6.16%,L1/TEX 只有 7.92%——计算单元基本在干等数据,这是教科书级的 memory-bound(访存瓶颈)知乎。这也符合向量加法的本质:每个元素只做1次加法,却要读2次写1次,算术强度太低,带宽先被吃满。

CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

定性规则可以总结成一张表:

SOL表现

瓶颈类型

下一步看哪

Memory高、SM低

访存瓶颈

Memory Workload Analysis

SM高、Memory低

计算瓶颈

Compute Workload Analysis / Instruction Statistics

两个都不高

延迟瓶颈(最难啃)

Warp State Statistics + Occupancy

前两种好办,第三种最磨人:两个都不高,说明 GPU 既没算满也没搬满,时间都花在"等"上——等数据到达、等同步、等调度。这时候要换工具面板,下面说。

第三步:三个分支,往下钻一层

分支一:访存瓶颈 → 看合并程度

打开 Memory Workload Analysis,核心看一件事:你的访存合并得好不好。官方文档里这张 Memory Chart 把存储层级的流量画得很直观:每一级的命中率、吞吐占峰值的百分比一目了然,哪一层在流血一眼就能看到NVIDIA官方文档

CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

这里需要对齐三个概念,也是 noinfra 那期《内存分析详解》讲透的内容哔哩哔哩

  • Request:一个 warp 执行一条访存指令发出的一次请求

  • Sector:显存系统处理数据的最小粒度,32字节

  • Wavefront:实际派发到显存子系统的一批 sector

理想情况下,一个 warp 的32个线程访问连续对齐的128字节,正好合成4个 sector——这是最省的形态。Leenzhou 的向量加法实测就是完美的 1/8:按元素算"应该"有 2,097,152 次 sector 级访问,实际只有 262,144 次,和理论推导完全吻合知乎

反过来,如果线程访问的地址零散跨行,一次请求就要扇出成大量 sector。报告里会直接标出 excessive sectors(超额扇区)。暮易在知乎连载的 FlashAttention 优化实录里有个震撼的数字:他通过调整 stmatrix 的布局加 padding,把 excessive sectors 从 600 多万直接干到 0知乎

顺便说一句 roofline 视角:如果 SOL 显示访存瓶颈,而你的算法算术强度本来就低(比如逐元素操作),那带宽打满就是终点,别折腾了;如果算术强度不低却打不满带宽,问题大概率出在合并和缓存利用上。

分支二:计算瓶颈 → 看指令构成

打开 Compute Workload Analysis 和 Instruction Statistics,看是哪条流水线在满负荷:FMA、ALU、Tensor Core 还是 LSU。如果目标吞吐对应的管道确实打满了,说明优化方向是减少指令数或换更强的指令。

这里埋着一个真实悬案,下面坑点部分细说。

分支三:延迟瓶颈 → 看 warp 在等什么

Warp State Statistics 面板会把每个周期的 warp 状态拆开,重点看停顿原因:

  • Long Scoreboard:在等全局内存的数据回来——典型延迟瓶颈,考虑预取、加大每线程工作量或提高并行度

  • Short Scoreboard:在等共享内存/L1 相关操作——查 bank conflict

  • Barrier:在等 `__syncthreads()`——同步点太密或block内负载不均

  • Math Pipe Throttle:数学流水线排队——这其实是好消息,说明你就是计算瓶颈,回到分支二

再配合 Occupancy 面板:Achieved Occupancy 离 Theoretical Occupancy 差多远?差得远的话,看是寄存器、共享内存还是 block 尺寸把占用率卡住了。

4个坑,都是过来人用小时为单位换来的

坑一:开着 debug 模式测性能。 知乎上 wild pointer 记录了一桩完整的"性能悬案":Softmax 加了 warp shuffle 优化,理论上寄存器路径更短,结果耗时反而暴增。他一层层查:NCU 里发现 Local Memory 有流量→怀疑函数调用压栈,加 `forceinline`→流量还在→用 `–ptxas-options=-v` 查寄存器溢出,是0→最后在 Instruction Statistics 里发现 MOV 指令比优化前多了近一倍,SASS 里 `__shfl_down_sync` 竟然变成了 CALL 调用。真相是 CUDA 编译选项里的 Generate GPU Debug Information(也就是 `-G`)没关——debug 模式下内联和 peephole 优化全被禁用。他原话:排查耗时数小时知乎结论:测性能永远用 Release 配置,别开 `-G`。

坑二:拿 ncu 跑出来的时间当真实性能。 有同学发现,加了 ncu 之后 cudaEvent 测出的 kernel 时间从 2ms 变成 1803ms,以为程序写崩了知乎。其实这是 NCU 的工作机制:为了采集几百个硬件计数器,同一个 kernel 要被重放很多轮,每轮重放前都要把显存状态恢复一遍,cudaEvent 计的是全部重放的总开销NVIDIA官方文档。真实性能看报告里的 Duration,或者干脆在不开 ncu 时单独计时。

CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

坑三:数据太小,带宽虚高。 还是 Leenzhou 的实验:他按实测数据反推带宽,发现算出来的值超过了 A6000 Ada 的理论峰值 960GB/s。不是超频了,是 NCU 多轮重放期间,他那点测试数据(N=1M 的 float 数组)早就整个住进了 96MB 的 L2 缓存,DRAM 流量被严重低估知乎结论:测带宽时数据量要明显大于 L2 容量,或者用 `–cache-control` 选项留意缓存行为。

坑四:把 occupancy 当越高越好的 KPI。 这周还有个反常识视频值得看:DeeparchWorks 的《GPU核越多越快吗?占用率与寄存器压力的反转》——核心更多、利用率满格、occupancy 更高,kernel 反而可能更慢哔哩哔哩。占用率只保证"有 warp 可调度",真正决定性能的是数据复用和流水线效率。暮易那个 FA 优化系列里也有同样的体会:从算术指令到 occupancy 挣扎的那一轮(G2),收益是所有轮次里最小的,真正的跃升来自 pipeline 重构(一轮从221干到727 TFLOPS)知乎知乎。NCU 给的规则提示也要带着怀疑看,他的原话是"ncu 的 FMA 提示是幻觉"——只要 kernel 还是 latency-bound,FMA 提示就没有意义知乎

CUDA入门教程学完了,kernel 还是慢?学会看 Nsight Compute:3步定位瓶颈,避开这4个坑

实操清单,存一下

场景

命令

快速看一眼

`ncu ./app`

全量指标

`ncu --set full ./app`

只看某个面板

`ncu --section MemoryWorkloadAnalysis ./app`

指定指标

`ncu --metrics dram__bytes_read.sum ./app`

跳过预热kernel

`ncu --launch-skip 4 --launch-count 1 ./app`

图形界面

`ncu-ui`

两条补充建议:程序里有多个 kernel 时,务必用 `–launch-skip` 和 `–launch-count` 圈定要分析的那一个,否则报告会混在一起;优化是迭代的活,把每轮的 `.ncu-rep` 存下来,在界面里做 baseline 对比,比凭记忆靠谱得多。

接下来学什么

按这周的更新节奏,给个顺手的学习序列:先看 noinfra 的《以GEMM为例,学会使用Nsight Compute》把面板过一遍哔哩哔哩。知乎上 Leezhou 的系列适合对照着读文字版推导知乎。再跟"弹幕教我写代码"的系列补合并访存和共享内存哔哩哔哩。想啃进阶案例,暮易的 FlashAttention 优化七连(56→986 TFLOPS)是目前中文社区少见的完整实录,每一轮改了什么、收益多少都记得很清楚知乎

最后一个提醒:Blackwell 这一代的工具链更新很快,CUDA 13.x 还在高频迭代,NCU 的面板和指标名也会跟着变,建议收藏官方 Profiling Guide 跟着版本看NVIDIA官方文档。路线本身——先定性、再钻一层、用证据说话——倒是不会过时的。

内容由AI生成

精选参考来源

1. 以 GEMM 为例,学会使用Nsight Compute

2. 以 GEMM 为例,学会使用Nsight Compute

3. Nsight Compute 内存分析详解:Request、Sector、Wavefront

4. CUDA 编程(三):从向量加法到 Nsight Compute 性能分析

5. GPU到底慢在哪?NCU带你看懂CUDA性能瓶颈【2】

6. 【CUDA 性能悬案】耗时暴增 、带宽打折的幽灵:硬件指令与软件抽象的分歧

7. Flash Attention CUDA Kernel 优化: 从 56 到 986 TFLOPS on sm103 — G2: 从算术指令到 Occupancy 的挣扎 (130→144)

8. Flash Attention CUDA Kernel 优化: 从 56 到 986 TFLOPS on sm103 — G6: Cluster 与 2CTA 探索 (727→880)

9. Flash Attention CUDA Kernel 优化: 从 56 到 986 TFLOPS on sm103 — G3: Fragment Reshape 与架构级突破 (144→227)

10. Flash Attention CUDA Kernel 优化: 从 56 到 986 TFLOPS on sm103 — G1: 一切的开始 (56→130)

11. GPU核越多越快吗?占用率与寄存器压力的反转

12. 2. Profiling Guide — NsightCompute 13.3 documentation

13. 3. Nsight Compute — NsightCompute 13.3 documentation

14. Flash Attention CUDA Kernel 优化: 从 56 到 986 TFLOPS on sm103 — G5: Pipeline 重构与双缓冲 (221→727)

15. Nsight Compute:指标和分析过程

0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章