先记住一句话
先测端到端时间线,再下钻热点 kernel;任何速度数字都必须绑定硬件、软件、shape、dtype、warmup、同步方式和正确性。
1. 先分清测量层级
| 层级 | 问题 | 常用工具 |
|---|---|---|
| 应用/请求 | 用户实际等多久?吞吐/尾延迟如何? | 服务 metrics、wall clock |
| CPU↔GPU 时间线 | launch gap、同步、通信、copy 在哪? | Nsight Systems、NVTX |
| 单 kernel | memory、compute、occupancy、stall 哪个限制? | Nsight Compute |
| 正确性 | 越界、race、未初始化访问? | Compute Sanitizer、tests |
2. GPU 是异步的
host API 返回通常不代表 GPU 已完成。直接在 Python/C++ launch 两侧读 CPU clock 可能只测到 enqueue。isolated GPU timing 用 CUDA events 记录同一 stream 的设备时间,或在 wall-clock 区间末端显式 synchronize;生产 end-to-end latency 则应保留真实排队和同步。
3. Warmup 与冷启动
首次迭代可能包含 context 创建、library handle、JIT/graph compile、autotune、memory allocator growth 与 page faults。分别报告 cold start 与 steady state;warmup 到行为稳定,但不要故意丢掉线上每次都会发生的初始化。
4. Nsight Systems:先看全局
在 CPU threads、CUDA API、GPU kernels、memcpy 和 NCCL 统一时间线上寻找:CPU launch gaps、隐式同步、串行 streams、H2D/D2H 未 overlap、许多 tiny kernels、collective stragglers。用 NVTX range 标出 dataloader、forward、backward、optimizer、prefill/decode,避免只面对一串 kernel 名字。
5. Nsight Compute:再看热点
关注 achieved bandwidth/compute throughput、memory transactions、cache hit、warp issue/stall reasons、register/shared-memory usage 与 occupancy。Roofline 把 kernel 放在 arithmetic intensity—performance 图上:贴 bandwidth roof 优先减少 bytes/提高 reuse,贴 compute roof 才优先更快 math/Tensor Core。
6. Occupancy 不是性能分数
高 occupancy 有利于隐藏 latency,却不保证 cache locality、instruction mix 或 ILP 好;有些 GEMM 用更多 registers 保持 accumulators,occupancy 较低仍更快。目标是足够 latency hiding 下的最大 throughput,而不是把 occupancy 调到 100%。
7. 可信 benchmark 协议
- 固定 GPU 型号、功耗/时钟策略、driver/CUDA/library versions;
- 记录 shape distribution、dtype、layout、batch/sequence、compile mode;
- 预热后重复足够次数,报告 median、分位数和波动;
- 避免与其他 workload 竞争,检查温度/降频;
- 含正确性、内存峰值和必要的 layout/copy/compile 成本;
- 服务测 TTFT/TPOT/p50/p95/p99,而不只平均 tokens/s。
8. Debugging 顺序
先缩成最小 reproducer,再开启同步 launch 定位报错边界;用 Compute Sanitizer 的 memcheck 查越界/非法访问、racecheck 查 shared-memory hazards;加入 launch config 与 shape assertions。异步错误常在后续 API 才浮现,最后报错行不一定是根因。
9. 性能回归要自动化
保留一组代表性 shapes、端到端场景和 correctness gates;在同类固定机器上运行,使用容忍噪声的统计阈值。既追踪 latency,也追踪 kernel count、compiled graph count、memory 与 task quality,防止“优化”只是换了语义。
10. 四个 benchmark 手算
例 1:异步假快
Host enqueue kernel 用 8 μs,GPU 实际运行 400 μs。不同步的 wall clock 会误报 8 μs、看似 50× 更快;CUDA events 或 sync boundary 才测 execution。
例 2:percentile
10 次 latency [9,9,10,10,10,10,11,11,12,30] ms,mean=12.2 ms,median=10 ms,max=30 ms。只报 mean 会掩盖 tail stall。
例 3:Amdahl 稀释
Hot kernel 占模型 20%,优化 30% 意味新 kernel 时间为原 0.7,端到端比例=0.8+0.2×0.7=0.94,总 speedup 仅 1/0.94=1.064×。
例 4:噪声门槛
Baseline 100±3 μs、candidate 97±3 μs,名义提升 3%,与 run-to-run noise 同量级。应增加 repetitions、固定 clocks/负载并做统计,而非宣称稳定回归。
某个 kernel 快 30% 不等于模型快 30%。Amdahl 定律、输入 pipeline、通信、CPU overhead 和其它 kernels 会稀释收益;只有端到端复测能证明价值。
自测
1. 何时用 Nsight Systems,何时用 Nsight Compute?
Systems 用于跨 CPU/GPU/通信的时间线和热点定位;Compute 用于解释选定 kernel 的硬件行为。
2. 为什么 CPU timer 容易低估 kernel 时间?
launch 是异步 enqueue,timer 停止时 GPU 可能尚未执行完。
3. 为什么要报告 tail latency?
平均值会掩盖排队、动态 batching、编译 miss 或长序列导致的少量极慢请求,而用户体验常由尾部决定。
官方资料
NVIDIA Nsight Compute Profiling Guide解释 metrics、sampling 与 Roofline;CUDA Best Practices Guide给出计时、有效带宽和优化验证方法。