跳到主要内容
CUDA编程与算子优化

第8章:性能分析工具链

掌握 Nsight Systems、Nsight Compute 和 PyTorch Profiler 三大性能分析工具,建立系统化的性能诊断能力

Nsight Systems Nsight Compute PyTorch Profiler 性能分析

优化的前提是精准诊断——不会用 Profiler 的优化都是盲猜。本章掌握 AI Infra 领域的三大核心性能分析工具:Nsight Systems(全链路时间线)、Nsight Compute(Kernel 级下钻)、PyTorch Profiler(框架级 op 视图),并给出一套通用的”找到瓶颈→对症下药”工作流。

📑 目录


1. 性能分析的两层视角

工具视角回答的问题
Nsight Systems系统级时间线”GPU 在等谁?哪个阶段最慢?”
Nsight ComputeKernel 级”这个 kernel 是 memory bound 还是 compute bound?”
PyTorch Profiler框架 op 级”我的模型里哪个 op 最耗时?”

典型流程:先用 Nsys 看宏观时间线,定位耗时最长/最异常的 kernel → 用 Ncu 下钻这个 kernel,找具体的 limiter。


2. Nsight Systems:全链路时间线

2.1 抓 trace

# 命令行(通用)
nsys profile -o my_trace --stats=true \
    --trace=cuda,nvtx,osrt,cudnn,cublas \
    python train.py

# PyTorch 训练:用 nvtx 标注关键阶段
import torch.cuda.nvtx as nvtx
with nvtx.range("forward"):
    out = model(x)
with nvtx.range("backward"):
    loss.backward()
with nvtx.range("optimizer"):
    optimizer.step()

2.2 打开 trace

nsys-ui my_trace.nsys-rep        # 图形界面

会看到一条时间线,行包括:

  • CPU 线程:Python 调用、CUDA API
  • CUDA Stream:Kernel 执行时间块
  • NVTX:你标注的范围
  • NCCL:通信 op
  • GPU Metrics:SM 利用率、HBM 带宽

2.3 找 GPU Idle Gap

GPU Stream:  ████____████____████____████
                ↑       ↑       ↑
             这些 gap 就是 GPU 空闲时间

GPU idle 的根因有几种:

Gap 来源症状解决
CPU 数据预处理慢gap 期间 CPU 线程在跑 PIL / decode / tokenizenum_workers > 0 多进程 dataloader
Host-Device 同步gap 期间是 cudaMemcpy 或 .item()减少同步、用 pinned memory
Kernel Launch Overheadgap 极小但密集CUDA Graph / 算子融合
多卡通信等待NCCL Stream 占满计算通信 overlap、梯度桶大小
调度器空转gap 大且无明显活动检查 Python GIL、scheduler 实现

2.4 实战命令

# 只 trace 第 100-103 步,避免 trace 文件过大
nsys profile --capture-range=nvtx --capture-range-end=stop \
    -c train_step --range-id=100-103 ...

# 自动统计,不用打开 GUI
nsys stats --report cuda_kernel_sum my_trace.nsys-rep

3. Nsight Compute:Kernel 级下钻

3.1 抓单个 kernel

# 抓所有 kernel,详细数据(很慢,只用于调试)
ncu -f -o report --set full python my_kernel.py

# 只抓特定 kernel,快得多
ncu -f -o report --kernel-name "my_softmax_kernel" \
    --launch-skip 100 --launch-count 5 \
    python my_kernel.py

# 命令行直接看报告
ncu --set basic ./my_app

3.2 打开报告

ncu-ui report.ncu-rep

3.3 关键面板

面板用途
GPU Speed of Light算力/带宽利用率,第一眼必看
Memory Workload AnalysisHBM/L2/Shared/Register 各层带宽占用
Compute WorkloadSM 各类指令利用率(FP32/FP16/Tensor)
Scheduler StatisticsWarp 状态(active/stalled/eligible)
Warp State看 Warp 在等什么(memory/sync/…)
Source / SASS行级耗时(需要 -lineinfo 编译)
Occupancy实际 vs 理论占用率

3.4 对比模式

ncu-ui --baseline old.ncu-rep new.ncu-rep

直接看新版相对旧版的提升/退化,优化前后对比一目了然。


4. SOL(Speed of Light)面板解读

SOL = “如果硬件资源完全打满,kernel 能跑多快”——你和这个上限的差距,就是优化空间。

4.1 三个核心数字

指标含义
SM%算力利用率(几乎所有计算单元都在用)
Memory%HBM 带宽利用率
Tensor%Tensor Core 利用率(独立计算)

4.2 判断 Bound

SM% > 80%, Memory% < 50%  →  Compute Bound,优化方向是减算力 / 用 Tensor Core
SM% < 50%, Memory% > 80%  →  Memory Bound,优化方向是减访存 / 提高 AI
两个都 < 50%               →  Latency Bound,Occupancy 不够,优化方向是改 Block Size / 减寄存器

4.3 实战例子

场景SM%Mem%诊断
GEMM(BM=128)92%30%Compute Bound,完美
Softmax15%85%Memory Bound,正常
Attention(无 Flash)35%95%Memory Bound,改 FlashAttention
LayerNorm10%70%Memory Bound + Latency Bound,需要融合
Bad GEMM(register spill)25%30%Latency Bound,降寄存器

4.4 如果 Compute Bound 但没用 Tensor Core

Compute Workload 面板的 Tensor Pipe Utilization——如果接近 0,说明你只用了 CUDA Core,改用 WMMA / cuBLAS 立刻能提升 5-10 倍。


5. PyTorch Profiler:框架级视图

5.1 基本用法

from torch.profiler import profile, ProfilerActivity, schedule

with profile(
    activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
    schedule=schedule(wait=1, warmup=1, active=3, repeat=2),
    on_trace_ready=torch.profiler.tensorboard_trace_handler('./logs/profile'),
    record_shapes=True,
    profile_memory=True,
    with_stack=True,
) as prof:
    for step in range(10):
        train_step()
        prof.step()

5.2 终端摘要

print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=20))

会看到一张表:每个 op 的 CPU/CUDA 时间、调用次数、平均耗时——能立刻锁定耗时大户。

5.3 TensorBoard 可视化

pip install torch-tb-profiler
tensorboard --logdir=./logs

会有几个标签页:

  • Overview:整体时间分布(GPU kernel / CPU exec / DataLoader / Optimizer)
  • Operator:按 op 类型分组的耗时
  • Kernel:按 GPU kernel 分组
  • Trace:类似 Chrome tracing 的时间线
  • Memory:显存使用曲线

5.4 chrome://tracing 看 trace

prof.export_chrome_trace("trace.json")
# 打开 chrome://tracing,加载 trace.json

适合细粒度分析单个 iteration。


6. 标准排查流程

6.1 训练慢

1. 跑一次 nsys profile,看时间线

2. GPU 利用率高吗?
   ├─ < 50% → 找 idle gap 来源(CPU 数据 / 通信 / sync)
   └─ > 80% → 进入第 3 步

3. 哪个 kernel 占时间最多?

4. ncu 抓那个 kernel,看 SOL
   ├─ SM% 高 + Mem% 低 → Compute bound,优化算法 / 用 Tensor Core
   ├─ SM% 低 + Mem% 高 → Memory bound,减访存 / 算子融合
   └─ 两者都低 → Latency bound,改 Block Size / 寄存器

6.2 推理慢

1. PyTorch Profiler 看 op 分布

2. 找耗时大户(通常是 Attention / GEMM / LayerNorm)

3. 该 op 已经是 SDPA / FlashAttention 了吗?
   ├─ 否 → 替换
   └─ 是 → 用 ncu 下钻看是否还有空间

4. KV Cache 显存够吗?
   ├─ 不够 → PagedAttention / 量化
   └─ 够 → 提高并发

6.3 OOM

1. torch.cuda.memory_summary() 看哪一步显存激增

2. torch.cuda.memory._record_memory_history → 上传 memory_viz

3. 找峰值的来源(激活? 优化器状态? 临时 buffer?)

4. 对症下药:
   ├─ 激活大 → Activation Checkpointing / 减 batch size
   ├─ 优化器大 → ZeRO / 8bit optimizer
   └─ 临时 buffer → 检查是否有 .clone() 没释放

✅ 自我检验清单

  • Nsys 实操:能用 nsys profile 抓一次训练 trace,在 GUI 中找到最长的 kernel
  • GPU idle gap:能根据 trace 判断 gap 来源(CPU / 通信 / sync / launch overhead)
  • NVTX 标注:能用 nvtx.range 标注 forward / backward / optimizer 三个阶段
  • Ncu 实操:能抓单个 kernel 的 ncu 报告,在 SOL 面板判断 bound 类型
  • Compute vs Memory bound:看 SOL 数字能立刻给出优化方向
  • Tensor Core 检查:能从 Compute Workload 面板看 Tensor Pipe Utilization
  • PyTorch Profiler:能集成到训练脚本,在 TensorBoard 中可视化
  • chrome://tracing:能导出 trace.json 并在 Chrome 中查看
  • OOM 排查:能用 memory_viz 工具找出显存峰值来源
  • 完整流程:面对一个”训练慢”的问题,能给出系统化的排查步骤

📚 参考资料

官方文档

教程与博客

  • NVIDIA GTC Profiling 系列 talk:每年都会更新最佳实践
  • Andrei Damian:How to Use Nsight Systems:实战入门
  • 方佳瑞:从 Nsight 报告看 LLM 推理优化

工具

  • PyTorch TensorBoard Profiler 插件:pip install torch-tb-profiler
  • Perfetto:https://ui.perfetto.dev/ —— 比 chrome://tracing 更强的 trace 可视化

系统级综述

  • AI Systems Performance Engineering(Chris Fregly, O’Reilly 2025):learning.oreilly.com —— Ch5 系统讨论 CUDA 编程与 profiling、Ch7 PyTorch 调优,把单点 profile 工具串成”全栈瓶颈定位”流程