4、性能分析工具入门:NVIDIA Nsight Systems、Nsight Compute、nvidia-smi的基本使用
好,咱们进入实战环节。前面聊了那么多带宽的理论,现在该看看怎么用工具抓住它了。
说实话,我见过不少工程师,代码写得飞起,一跑起来性能拉胯。问他为什么慢,答不上来。为什么?因为没用量化工具。凭感觉优化,那是玄学。今天我就带你认识三把最趁手的「手术刀」。
4.1 第一把刀:nvidia-smi —— 系统级监控
这是最基础的,也是我每天必敲的命令。它就像汽车的仪表盘,告诉你发动机转速、油温、水温。
基本用法
nvidia-smi
敲下去,你会看到当前GPU的型号、显存使用、温度、功耗、风扇转速。嗯,这里要注意:显存占用 ≠ 显存带宽利用率。很多人看到显存用了80%就慌了,其实不一定有问题。
我常用的几个参数
nvidia-smi -l 1:每秒刷新一次,持续监控。我习惯开着它跑程序,看显存和功耗曲线。nvidia-smi dmon -s pucvmet:更详细的监控模式,能看到PCIe带宽、电源状态。nvidia-smi --query-gpu=memory.used,utilization.memory --format=csv:输出CSV格式,方便脚本处理。
4.2 第二把刀:Nsight Systems —— 时间线分析
这个工具,说白了就是给程序拍X光片。它能告诉你CPU和GPU各自在干什么,哪个阶段在等数据。
什么时候用它?
当你发现程序跑得慢,但不知道慢在哪一段。比如:是数据加载慢?还是计算慢?还是同步开销大?
基本用法
nsys profile -o my_profile ./my_app
运行完后会生成一个 .nsys-rep 文件。用Nsight Systems GUI打开,你会看到一条时间轴。
我重点关注什么?
- GPU Kernels:看每个kernel的执行时间。如果某个kernel特别长,点进去看。
- MemCpy (H2D/D2H):主机到设备、设备到主机的数据拷贝。如果这里占了大量时间,说明数据传输是瓶颈。
- CPU Activity:看CPU在忙什么。有时候CPU在等GPU,有时候GPU在等CPU。
避坑指南: 我曾经遇到一个项目,GPU利用率只有30%。用Nsight Systems一看,发现每次kernel启动前,CPU都在做一次同步等待。去掉那个多余的 cudaDeviceSynchronize(),利用率直接飙到85%。
4.3 第三把刀:Nsight Compute —— 内核级剖析
这是最精细的工具。如果说Nsight Systems是看全局,那Nsight Compute就是看每个kernel的内部细节。它能告诉你:你的kernel到底是不是带宽瓶颈。
基本用法
ncu -o my_kernel_profile ./my_app
同样生成一个 .ncu-rep 文件。打开后,你会看到密密麻麻的指标。
我只看这几个关键指标:
| 指标 | 含义 | 我的判断标准 |
|---|---|---|
| Memory Throughput | 实际达到的显存带宽 | 如果远低于理论带宽(比如A100是2TB/s,你只跑到200GB/s),说明有瓶颈 |
| L1/L2 Hit Rate | 缓存命中率 | 命中率低,说明数据局部性差,带宽浪费在重复加载上 |
| Occupancy | SM上活跃的warp数量 | 如果Occupancy低,可能是寄存器或共享内存用太多 |
| Compute Utilization | 计算单元利用率 | 如果Memory Throughput高但Compute Utilization低,就是典型的带宽瓶颈 |
怎么判断是不是带宽瓶颈?
你想想看,如果Memory Throughput接近理论带宽,但Compute Utilization很低,那你的kernel就是在「等数据」。说白了,计算单元在摸鱼,因为数据喂不过来。
4.4 三把刀怎么配合使用?
我个人的工作流是这样的:
- 先用nvidia-smi:看看整体资源使用情况,有没有异常。
- 再用Nsight Systems:找到最耗时的阶段,是数据拷贝还是kernel执行。
- 最后用Nsight Compute:针对最耗时的kernel,深入分析是不是带宽瓶颈。
举个例子。有一次我优化一个图像处理程序。先用nvidia-smi发现显存占用高但利用率低。然后用Nsight Systems看到,大部分时间花在了一个叫 filter_kernel 的kernel上。最后用Nsight Compute分析这个kernel,发现Memory Throughput只有理论带宽的30%,L1命中率不到10%。
嗯,问题找到了。数据访问模式太随机,缓存根本帮不上忙。后面我们就会讲怎么通过合并访问、共享内存来优化它。
好了,这一章就到这。下一章我们开始讲怎么用这些工具定位具体的带宽瓶颈,我会拿一个真实的代码案例来演示。