Community编程与开发github.com

jiweibo/perf-nsight-compute-analysis

分析 NVIDIA Nsight Compute (ncu) 性能分析输出:SOL% 瓶颈分类、屋顶线分析、占用率诊断、内存层次分析、Warp 停顿分析、指标解读,以及对 .ncu-rep 报告进行程序化分析。不用于内核编写或代码生成、Nsight Systems (nsys)、主机端分析或系统级分析。

perf-nsight-compute-analysis 是什么?

该技能是一个专业化的数据驱动分析系统,专注于通过 NVIDIA Nsight Compute (ncu) 工具剖析单个 CUDA 内核的性能。它帮助开发者将内核运行速度归类为计算受限、内存受限或延迟受限,并依据 Speed of Light (SOL%) 指标(即达到 GPU 理论峰值的百分比)提供有针对性的优化建议。技能核心原则包括严格的引用数据完整性——每项指标都必须附有原始 ncu 输出——以及按瓶颈类型进行有步骤的深入分析流程。它支持在命令行中进行快速 SOL% 检查、针对特定性能问题(如 bank 冲突、寄存器压力、Warp 停顿)进行精确部分诊断,以及基于 Python ncu_report 模块进行程序化 .ncu-rep 报告分析。该技能明确不适用于系统级分析(应使用 nsys)或内核编写/代码生成;它专门用于降低单个 CUDA 内核执行时间的深层根源分析。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jiweibo/skills/tree/HEAD/perf-nsight-compute-analysis

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Nsight Compute 分析

NVIDIA Nsight Compute (ncu) 对单个 CUDA 内核进行性能分析,以确定它们为何运行缓慢以及如何优化。它将 GPU 吞吐量测量为理论峰值(Speed of Light / SOL%)的百分比,从而实现系统化的瓶颈分类和有针对性的优化。

使用时机

当你遇到以下情况时,可调用此技能:

  • 触发条件:用户想要对 CUDA 内核进行性能分析、分析 ncu 输出、解读 .ncu-rep 报告,或优化 GPU 内核性能
  • 症状:内核运行速度低于预期、GPU 利用率低、需要分类计算受限 vs 内存受限、占用率问题
  • 关键词:"ncu"、"nsight compute"、"SOL%"、"speed of light"、"内核性能分析"、"计算受限"、"内存受限"、"延迟受限"、"占用率"、"屋顶线"、"warp stalls"、"缓存命中率"、"ncu-rep"

不得将此技能用于:

  • 系统级分析(请使用 Nsight Systems / nsys)
  • CUDA API 跟踪或 CPU-GPU 时间线分析(请使用 nsys)
  • 无需性能分析的 GPU 监控(请使用 nvidia-smi)

要求

依赖项版本说明
CUDA Toolkit>=11.0包含 ncu
ncu 二进制文件驱动程序支持的版本Nsight Compute 2026.3 需要与 CUDA 13 兼容的驱动程序。或设置 $NCU 环境变量
NVIDIA GPUTuring+Volta 需要 Nsight Compute 2025.2 或更早版本

权限:ncu 在容器中可能需要 sudo、CAP_SYS_ADMIN 或 --privileged。ncu -v 仅打印版本;缺少权限会在第一个内核被分析时显示为 ERR_NVGPUCTRPERM。

原则

数据完整性

这是一个数据驱动的分析系统。你呈现的每个数字都必须有权威来源。 请毫无例外地遵循以下规则:

  1. 先引用再解读。 在呈现 ncu 输出的指标时,始终先展示你实际运行的 ncu 命令以及相关的原始输出(CSV 行、指标值),然后再陈述任何数字结论。
  2. 绝不虚构指标。 如果 ncu 失败、返回意外输出,或者你无法运行它,请明确说明。不要编造看起来合理的数字。诚实的"性能分析失败"优于虚假数据。
  3. 归因每个值。 对于你引用的每个指标(SOL%、持续时间、占用率、吞吐量),读者必须能够将其追溯回你展示的原始 ncu 输出中的特定行。

SOL% 心智模型

Speed of Light (SOL%) 衡量内核运行接近 GPU 理论峰值的程度:

  • 计算 SOL% (Compute (SM) Throughput) = 最繁忙 SM 单元的吞吐量占其峰值的百分比
  • 内存 SOL% (Memory Throughput) = 最繁忙内存单元(DRAM、L2、L1、共享内存)的吞吐量占其峰值的百分比

较高的指标通常揭示瓶颈类型。将其作为主要的分类信号。两者可能同时较高:此时内核已达到其算法的硬件极限。

分类阈值

计算 %内存 %瓶颈下一步
>60<40计算受限ComputeWorkloadAnalysis 部分
<40>60内存受限MemoryWorkloadAnalysis 部分
<40<40延迟受限LaunchStats + Occupancy 部分
40-6040-60均衡使用详细部分进行更深入分析
>60>60接近硬件极限算法变更;检查两个工作负载部分

附加信号:

  • 持续时间 <10us 且启动次数多 -> 启动开销受限(先使用 nsys)
  • 两者均 <40% 但占用率 >50% -> 指令受限(检查 InstructionStats)

SOL% 性能水平

SOL%水平行动
>80%优秀仅需微调
60-80%良好针对性优化
40-60%一般需要重大优化
<40%差需要重大重构

按部分优先分析

始终使用有针对性的 --section 标志,而不是使用 --set 进行批量收集。单独的部分更快、更精准。仅当需要广泛探索时,才升级到 --set basic 或 --set detailed。

ncu vs nsys

工具范围开销目的
nsys系统级5-10%找出要优化的内核
ncu内核级慢 10-100 倍理解内核为何慢

先使用 nsys 识别按 GPU 时间排名靠前的内核,然后使用 ncu 对这些特定内核进行深入分析。

工作流程

根据请求选择你的路径:

  • 知识查询(使用哪些指标、--section vs --set、如何过滤内核):直接从下面的原则、命令参考和参考资料中回答。不要运行 ncu。
  • 快速诊断(分类瓶颈、检查 SOL%):仅执行步骤 1。如果用户想要更多信息,则升级。
  • 特定诊断(bank 冲突、寄存器压力、占用率):快速 SOL% 检查(步骤 1),然后直接进入步骤 2 中的相关部分。
  • 深度分析(详细报告、优化建议):完整步骤 1-5。在你的最终回复中呈现包含所有关键指标(SOL%、持续时间、占用率)的完整结构化报告——不要将报告拆分到多条消息中,也不要将其替换为简短摘要。

步骤 0:验证 ncu

ncu -v
# 或:$NCU -v

如果未找到,请确保已安装 CUDA toolkit 或设置 NCU 环境变量指向二进制文件路径。

步骤 1:SOL% 诊断

始终以 SpeedOfLight 开始分类瓶颈:

ncu --section SpeedOfLight --csv \
    --kernel-name regex:"KERNEL" \
    --launch-skip 5 --launch-count 3 \
    -- COMMAND

从输出中读取 Compute (SM) Throughput 和 Memory Throughput。使用上述阈值进行分类。

步骤 2:使用针对性部分升级

基于步骤 1 的分类,添加部分:

分类添加的部分
计算受限ComputeWorkloadAnalysis
内存受限MemoryWorkloadAnalysis
延迟受限LaunchStats、Occupancy
Warp 停顿WarpStateStats、SchedulerStats
需要指令分解InstructionStats

在诊断延迟受限内核时,始终包含 LaunchStats 和 Occupancy。这些能揭示寄存器压力、共享内存限制和块大小问题。

示例 -- 内存受限深度分析:

ncu --section SpeedOfLight --section MemoryWorkloadAnalysis --csv \
    --kernel-name regex:"embedding_lookup" \
    --launch-count 3 \
    -- python script.py

示例 -- 计算受限深度分析:

ncu --section SpeedOfLight --section ComputeWorkloadAnalysis --csv \
    --kernel-name regex:"gemm|nvjet" \
    --launch-count 3 -- python script.py

示例 -- 占用率调查:

ncu --section SpeedOfLight --section LaunchStats --section Occupancy --csv \
    --kernel-name regex:"small_kernel" \
    -- python script.py

步骤 3:屋顶线分析(可选)

用于直观理解计算与内存的平衡。屋顶线部分是图表:在 CLI 上,它们仅在 --print-details all 时打印,这会列出图表背后的数字(达到和峰值的工作量与通信量)。要查看图表,请使用 -o 保存报告并在 Nsight Compute UI 中打开。

ncu --section SpeedOfLight_RooflineChart --print-details all \
    --kernel-name regex:"KERNEL" -- COMMAND

对于特定精度层次结构屋顶线:

# FP16 内核
ncu --section SpeedOfLight_HierarchicalHalfRooflineChart --print-details all \
    --kernel-name regex:"KERNEL" -- COMMAND

# Tensor core 内核
ncu --section SpeedOfLight_HierarchicalTensorRooflineChart --print-details all \
    --kernel-name regex:"KERNEL" -- COMMAND

解读:内核位于脊点左侧 = 内存受限;右侧 = 计算受限;远低于两个屋顶 = 延迟/占用率问题。请参阅 references/roofline-analysis.md。

步骤 4:解读与优化

  1. 从 SOL% 分类中识别主导瓶颈
  2. 在 references/bottleneck-guide.md 中查找详细的分析和优化策略
  3. 首先应用影响最大的优化
  4. 重新分析以验证改进并检测瓶颈转移

步骤 5:验证

优化后重新分析相同的内核:

ncu --section SpeedOfLight --csv \
    --kernel-name regex:"optimized_kernel" \
    --launch-count 3 \
    -- python optimized_script.py

比较:吞吐量百分比是否增加?持续时间是否减少?瓶颈类型是否发生变化?

分析 JIT 编译的内核(Triton/cuTile/CuTeDSL)

JIT 编译的内核在首次调用时会触发自动调优。隔离实际执行:

  1. 先预热:运行内核 3-5 次以完成 JIT 编译和自动调优,然后 torch.cuda.synchronize()。
  2. 使用分析器标记:使用 cudaProfilerStart()/cudaProfilerStop() 包围测量区域。
  3. 使用 --profile-from-start off 以便 ncu 仅捕获标记区域:
# 预热(JIT + 自动调优)
for _ in range(5):
    result = kernel(inputs)
torch.cuda.synchronize()

# 仅分析稳态
 torch.cuda.cudart().cudaProfilerStart()
 for _ in range(3):
    result = kernel(inputs)
    torch.cuda.synchronize()
 torch.cuda.cudart().cudaProfilerStop()
ncu --profile-from-start off --section SpeedOfLight --csv \
    --kernel-name regex:"target_kernel" \
    --launch-count 3 -- python script.py

替代方案:使用 --launch-skip N 跳过自动调优启动。有关 NVTX 范围和重放模式的替代方案,请参阅 references/advanced-profiling.md。

程序化报告分析

使用 ncu_report Python 模块(位于 Nsight Compute 安装目录的 extras/python/ 中)从 .ncu-rep 或 .ncu-repz 文件中提取指标:

import ncu_report

ctx = ncu_report.load_report("report.ncu-rep")
for rng in ctx:
    for action in rng:
        name = action.name()
        # SpeedOfLight 的 "Compute (SM) Throughput" 和 "Memory Throughput"
        compute = action["sm__throughput.avg.pct_of_peak_sustained_elapsed"].as_double()
        memory = action["gpu__compute_memory_throughput.avg.pct_of_peak_sustained_elapsed"].as_double()
        duration = action["gpu__time_duration.sum"].as_uint64()

        if compute > 60:
            classification = "compute-bound"
        elif memory > 60:
            classification = "memory-bound"
        else:
            classification = "latency-bound"

        print(f"{name}: {classification} (compute={compute:.1f}%, mem={memory:.1f}%, {duration}ns)")

有关完整 API(IContext、IRange、IAction、IMetric 类),请参阅 references/python-report-api.md。

输出格式

CSV 输出(用于脚本编写和自动化分析):

ncu --csv --section SpeedOfLight --kernel-name regex:"KERNEL" -- COMMAND
ncu --csv --page raw --section SpeedOfLight -- COMMAND   # 所有指标平铺

默认 CSV 每行包含一个指标。其列包括 ID(分析的启动)、Kernel Name、Section Name、Metric Name、Metric Unit 和 Metric Value;规则结果是填入 Rule Name、Rule Description 和 Estimated Speedup 的行。Metric Name 可能跨部分重复(Memory Throughput 在 SpeedOfLight 中是 %,在 MemoryWorkloadAnalysis 中是 字节/秒),因此也需要按 Section Name 过滤。--page raw 每行对应一次启动,每列对应一个指标,并有第二行的单位。值使用基本单位(ns、hz、%)。

在分析期间,ncu 的 ==PROF== 行和应用程序自身的输出会与 CSV 共享标准输出。为获得干净的 CSV,请将报告写入文件然后读取:

报告文件(用于后续分析):

ncu -o report.ncu-rep --section SpeedOfLight -- COMMAND
ncu --import report.ncu-rep --csv                       # 每行一个指标
ncu --import report.ncu-rep --csv --page raw            # 每行一次启动

为 -o 指定扩展名:无扩展名时,Nsight Compute 2026.3 及更新版本写入 zstd 压缩的 report.ncu-repz,旧版本写入 report.ncu-rep。--import 和 ncu_report 均可读取两者。

关键指标行(Metric Name 值):

Metric NameSection含义
DurationSpeedOfLight执行时间
Compute (SM) ThroughputSpeedOfLight计算峰值的 %
Memory ThroughputSpeedOfLight最繁忙内存单元峰值的 %
SM FrequencySpeedOfLight分析运行的时钟频率
Achieved OccupancyOccupancy活跃 warp / 最大 warp (%)

成功指标:

  • 输出中存在 SOL% 值 -> 分析成功
  • Duration 值合理(不为 0 或极大)
  • 当 --launch-count > 1 时捕获了多次启动

示例

示例:分类一个 GEMM 内核

Blackwell 上的 cuBLAS GEMM 内核名为 nvjet_*,因此匹配这两个名称:

ncu --section SpeedOfLight --csv \
    --kernel-name regex:"gemm|nvjet" \
    --launch-skip 5 --launch-count 3 \
    -- python train.py

B200 上 FP16 4096x4096 矩阵乘法的输出(列和行已精简):

"ID",...,"Kernel Name",...,"Section Name","Metric Name","Metric Unit","Metric Value",...
"0"...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Memory Throughput","%","38.38",
"0"...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Duration","ns","97600",
"0"...,"nvjet_sm100_hsh_128x256_64x6_2x2f_2cta_h_bz_NNT",...,"GPU Speed Of Light Throughput","Compute (SM) Throughput","%","77.11",

解读:计算受限(计算 77.1%,内存 38.4%)。下一步:使用 --section ComputeWorkloadAnalysis 检查 Tensor Core 使用情况。

示例:诊断一个内存受限的 Embedding 内核

PyTorch 的 embedding lookup 执行 vectorized_gather_kernel,因此也要匹配它:

ncu --section SpeedOfLight --section MemoryWorkloadAnalysis --csv \
    --kernel-name regex:"gather|index|embedding" \
    --launch-count 3 -- python train.py

在输出中检查 L1/L2 缓存命中率:命中率低表明...

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能