优化 GPU 程序的第一原则:先测量,再动手。三件工具各管一段。
第一层:nvidia-smi
看的是「整卡状态」:显存占用、利用率、功耗:
nvidia-smi --query-gpu=utilization.gpu,memory.used,power.draw \
--format=csv -l 1
利用率低 + 显存占用高 → 大概率是访存瓶颈;两者都低 → 可能是 数据没喂饱或者卡在 CPU 侧。
第二层:PyTorch Profiler
看的是「算子级时间线」,定位哪几个 kernel 吃掉了时间:
from torch.profiler import profile, ProfilerActivity
with profile(activities=[ProfilerActivity.CUDA]) as prof:
model(input)
print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
记住两个数字:cuda_time(kernel 耗时)与 self_cuda_time
(不含子调用)。两者差距大说明时间花在框架调度而非计算。
第三层:Nsight Compute(ncu)
看的是「kernel 内部细节」,逐 kernel 给出:
- 计算吞吐:SM 利用率、指令吞吐;
- 访存:L1/L2 命中率、DRAM 带宽利用率;
- 调度:warp 停顿原因分布。
ncu --set full --launch-count 3 python train.py
排查顺序
- 显存是否接近上限 → 减小 batch / 优化缓存;
- 时间是否集中在少数 kernel → 聚焦优化热点;
- kernel 是 compute-bound 还是 memory-bound → 决定优化方向;
- 内存受限 → 合并访存、用共享内存、减少冗余读写。
指标是线索不是结论:一个 kernel 慢,可能是它自己的问题, 也可能是前一个 kernel 没刷完缓存、数据布局差导致的。