3. Profiling工具入门
说实话,很多同学写CUDA代码,跑通了就觉得万事大吉。但性能怎么样?瓶颈在哪?完全没概念。我刚开始做GPU优化那会儿,也犯过这毛病。直到有一次,一个看起来挺简单的kernel,怎么调都跑不满,折腾了两天。后来一用profiling工具,才发现是全局内存访问模式出了问题。嗯,从那以后,我写代码必做profiling。
这一章,咱们就聊聊NVIDIA的几款核心profiling工具。说白了,它们就是你的“GPU听诊器”。
3.1 NVIDIA Nsight Systems:宏观视角的“时间轴”
Nsight Systems,我习惯叫它“Nsys”。它主要看的是整个应用的时间线。CPU在干嘛?GPU在干嘛?数据传输花了多久?kernel执行和内存拷贝有没有重叠?这些宏观问题,用它看最清楚。
3.1.1 安装与配置
安装其实很简单。去NVIDIA官网下载,或者用包管理器。我个人习惯用命令行安装,干净利落。
# Ubuntu/Debian
sudo apt-get install nsight-systems
# 或者下载 .run 文件
chmod +x NsightSystems-linux-public.run
sudo ./NsightSystems-linux-public.run
装好后,终端敲 nsys 就能看到帮助信息。Windows用户直接双击桌面图标就行。
3.1.2 基本使用:抓取一次Profile
抓取profile,最常用的就是 nsys profile 命令。后面跟上你的可执行文件。
nsys profile -o my_profile ./my_cuda_app
这条命令会运行 my_cuda_app,并把结果保存到 my_profile.qdrep 文件里。 -o 指定输出文件名。
你想想看,如果我只想抓kernel执行,不想看API调用,怎么办?加个 -t cuda 参数就行。
nsys profile -t cuda -o kernel_only ./my_cuda_app
这招我在排查“kernel启动开销过大”时经常用。只关注CUDA相关事件,数据量小,分析起来也快。
3.1.3 图形界面:可视化时间线
抓完profile,用 nsys-ui 打开 .qdrep 文件。你会看到一个类似Gantt图的时间轴。
上边是CPU活动,下边是GPU流。不同颜色代表不同事件:
- 紫色:内存拷贝(Memcpy)
- 绿色:Kernel执行
- 黄色:CUDA API调用
一眼就能看出,你的程序是“计算密集”还是“访存密集”。我曾经优化过一个模型,一看时间线,好家伙,80%的时间都在做Host到Device的数据拷贝。那还优化啥kernel?先搞异步传输啊!
3.2 Nsight Compute:微观视角的“手术刀”
Nsight Compute,简称“Ncu”。如果说Nsys是看全局的,那Ncu就是盯着单个kernel,看它的内部细节。指令吞吐、内存带宽、占用率……这些关键指标,全靠它。
3.2.1 基本操作:Profile单个Kernel
用ncu profile一个kernel,命令也很直接:
ncu -o my_kernel_profile ./my_cuda_app
它会运行你的程序,并生成 .ncu-rep 文件。默认情况下,ncu会profile所有kernel。如果只想看某一个,可以用 --kernel-name 过滤。
ncu --kernel-name "myKernel" -o single_kernel ./my_cuda_app
这个功能特别实用。项目大了,kernel几十个,一个个看太费劲。先定位到最耗时的那个,再用ncu深挖。
3.2.2 关键性能计数器解读
打开 .ncu-rep 文件,你会看到一堆指标。别慌,咱们抓重点。
| 指标名称 | 含义 | 理想值 |
|---|---|---|
| Occupancy | 每个SM上活跃的warp数量与最大warp数量的比值 | 越高越好,但并非绝对 |
| Memory Throughput | 全局内存的读写吞吐量 | 接近理论峰值 |
| Compute Throughput | 计算单元的利用率 | 接近理论峰值 |
| L1/L2 Hit Rate | 缓存命中率 | 越高越好 |
| Warp Stall Reasons | warp停顿的原因(如等待数据、等待计算) | 无停顿最佳 |
举个例子。有一次我优化一个矩阵乘法,Occupancy很高,但Memory Throughput很低。我一看Warp Stall Reasons,发现大部分warp都在“等待数据”。这说明什么?说明内存访问模式有问题,导致缓存命中率低。后来改成共享内存,吞吐量直接翻倍。
3.3 命令行Profiling:nvprof与ncu
老玩家可能还记得 nvprof。它是CUDA 10之前的官方profiling工具。现在虽然被ncu取代了,但很多老项目还在用。我建议你至少知道它怎么用,万一遇到老代码呢?
3.3.1 nvprof(经典但已弃用)
nvprof --print-gpu-trace ./my_cuda_app
这条命令会打印出每个kernel的耗时、占用率、内存传输量等。简单粗暴,适合快速看一眼。
3.3.2 ncu(现代推荐)
ncu的命令行模式更强大。除了生成报告,还能直接输出文本结果。
ncu --set full --page details ./my_cuda_app
--set full 会收集所有指标,--page details 会显示详细分析。适合在无图形界面的服务器上使用。
我个人习惯在开发机上用图形界面,在集群上用命令行。两者结合,效率最高。
3.4 生成性能分析报告
分析完数据,怎么给别人看?或者怎么存档?NVIDIA提供了报告导出功能。
3.4.1 从Nsight Systems导出
在Nsys的图形界面里,点 File -> Export。可以导出为 .csv 或 .txt 格式。我一般导出CSV,方便用Python做二次分析。
3.4.2 从Nsight Compute导出
在Ncu的图形界面里,点 File -> Export Report。可以导出为 .csv、.json 或 .html 格式。HTML格式最直观,可以直接发给同事看。
我曾经给团队做过一次性能优化分享,就是把ncu的报告导出成HTML,然后贴在Wiki上。大家一看就懂,省了不少口舌。
3.5 本章知识体系
下面这张图,帮你理清本章的核心逻辑。
这张图展示了本章的核心脉络。从宏观的Nsight Systems,到微观的Nsight Compute,再到灵活的命令行工具,最终都指向一个目标:生成可读的性能分析报告,指导我们做优化。
好了,工具就介绍到这儿。下一章,咱们会拿一个实际的kernel,一步步演示怎么用这些工具找到性能瓶颈。到时候,你会看到这些计数器到底怎么用。