关于 deepstream-profile-pipeline
这是用于创建并测量高效 NVIDIA DeepStream 流水线的性能分析技能。它根据推理吞吐量和硬件上限推导配置,再用 Nsight Systems 命令行报告端到端及插件耗时。
主要功能
- 01应用面向性能的流水线默认配置
- 02测量推理批量大小平台点
- 03根据 GPU 上限推导设置
- 04使用 Nsight Systems 命令行分析
- 05报告各插件的 NVTX 耗时
适用场景
- 01根据目标流数量优化新流水线
- 02测量 GPU 与推理吞吐上限
- 03定位影响端到端耗时的流水线阶段
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nvidia/ skills --skill deepstream-profile-pipeline安装后在 Claude Code 中输入/deepstream-profile-pipeline确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BENCHMARK.mdREADME.mdrequirements.txtskill-card.mdskill.oms.sigevals/evals.jsonreferences/boundedness-rules.mdconfig-derivation-rules.mdhw-ceiling-formulas.mdnsys-cli-recipes.mdnvtx-coverage.mdscripts/capacity_report.pytests/__init__.pyREADME.mdtest_capacity_report.py详细介绍
DeepStream 性能分析技能
基于性能分析创建流水线。当用户表示希望构建高效的 DeepStream 流水线时,此技能会用两个实测数值——推理平台批次和硬件上限——取代猜测,并据此推导其他所有配置。随后使用 Nsight Systems 对端到端流水线进行性能分析,并报告各插件的 NVTX 耗时。
**与模型和流水线无关。**此技能仅假设推理元素为 nvinfer 或 nvinferserver(因此可通过标准配置设置模型维度、精度和批次参数)。它适用于检测(有或没有跟踪器)、分类、分割、VLM 和嵌入流水线。源可以是文件、RTSP、USB 摄像头,也可以是任意组合。此技能会读取用户的实际配置,以确定模型维度、目标 FPS 和源属性——不会假设任何特定模型、编解码器或分辨率。
**限制。**仅限终端操作。使用
nsys profile进行采集,并使用nsys stats提取数据。 不要依赖 Nsight Lens 或任何 GUI。
触发时机
在创建流水线时,当用户的请求体现出效率诉求时,启用此技能。具体触发条件:
- “构建一个高效 / 快速 / 性能出色 / 优化过的流水线”
- “给我一个能在这块 GPU 上良好运行的流水线”
- “对这个流水线进行基准测试 / 性能分析 / 测量 / 调优 / 优化”
- “我想以 M FPS 运行 N 路流”
- “这块 GPU 最多能处理多少路流”
- 用户明确要求使用
nsys或 Nsight
对于没有性能诉求的普通请求,例如“构建一个流水线”/“显示这个视频”/“保存这个流”,改用 deepstream-generate-pipeline 技能。
6 阶段流程
按顺序执行各阶段。阶段 0 在生成流水线之前执行,因此用户一开始就能获得经过性能调优的骨架。阶段 1–5 用于测量和验证。
阶段 0 — 预设应用(创建流水线时)
触发条件:编码 Agent 即将生成新的 DS 流水线,且用户的提示词表达了效率意图(见上文“触发时机”)。
操作:无需询问,预先应用以下默认值。用户无需了解这些设置,只需获得配置妥当的流水线。
| 参数 | 默认值 | 跳过条件 |
|---|---|---|
nvinfer.network-mode | 如果 int8-calib-file=<path> 指定的路径中存在校准文件,则设为 1(INT8);否则设为 2(FP16)。绝不使用 FP32。 | 模型没有 INT8 校准文件,且用户明确要求使用“FP32”。 |
nvinfer.model-engine-file | 预构建的 .engine 路径 | 始终设置。测量前强制进行一次预构建。 |
nvinfer.infer-dims | 与模型原生输入匹配的 3;<H>;<W> | 始终设置,即使 ONNX 模型具有静态形状也无妨。 |
nvstreammux.batch-size | 微基准测试优化前设为 min(N_streams, 16) | — |
nvstreammux.width / height | 模型的原生输入尺寸(从 nvinfer 配置的 infer-dims=3;H;W 中读取) | 用户明确要求 muxer 使用源视频原生分辨率。 |
nvstreammux.batched-push-timeout | 1e6 / source_fps µs(30 fps 时为 33333) | — |
nvstreammux.nvbuf-memory-type | 0(NVMM) | — |
解码器 num-extra-surfaces | min(batch_size, 5) | — |
解码器 cudadec-memtype | 0(NVMM) | — |
| Sink | 基准测试版本使用 fakesink sync=False | 用户要求屏幕显示或磁盘录制(此时保留 OSD/tiler/encoder/sink,并生成两个版本)。 |
| OSD + tiler | 省略 | 用户要求可见输出。 |
Tracker ll-config-file | config_tracker_NvDCF_max_perf.yml(随 DS 9.0 提供的性能调优版 NvDCF 预设) | 不存在 Tracker。 |
Tracker tracker-width / height | 480 / 288 | — |
Tracker enable-batch-process(位于链接的 YAML 中) | 1 | — |
| source 与 pgie 之间的 Queue | max-size-buffers = batch_size × 4 | 用户未要求添加 Queue(较少见)。 |
| Kafka/消息队列 | max-size-buffers=2, leaky=2 | 不使用 Kafka。 |
解码侧 PerfMonitor | 添加(除 pgie 侧外) | 流水线为 nvurisrcbin → pgie 直接连接,中间没有 Queue。 |
**阶段 0 的作用:**如果没有此阶段,每条新生成的流水线都会从优先显示的默认配置开始,阶段 1–5 就需要花时间修复本可避免的问题。阶段 0 是一道“从一开始就不要写出糟糕流水线”的关卡。
学生 / API 用户不会看到这些参数。该技能向用户返回的内容会使用通俗英文(FPS、流数量、观察到的瓶颈),而非参数名称。
验证流程(阶段 1–5)
按顺序运行各阶段。不要跳过任何阶段;后续阶段依赖前面阶段的输出。
阶段 1 — NVTX 覆盖检查
DeepStream 插件会原生发出 NVTX 范围;自定义插件和纯 GStreamer 核心元素(queue、tee、h264parse 等)则不会。在分析性能之前,列出流水线使用的元素并逐一分类。
- 读取流水线定义(gst-launch 字符串或
pipeline.py)。 - 在 references/nvtx-coverage.md 中查找每个元素。
- 将其分类为 已覆盖(在此 DS / 镜像 / nsys 组合中会发出 NVTX)或 未插桩。
- **MVP 规则:**该技能优先使用逐插件 NVTX 作为确认依据,但不作强制要求。解码瓶颈诊断依据微基准测试特征和
nvidia-smi dmon;计算瓶颈诊断依据 CUDA 内核组合;内存复制诊断依据cuda_gpu_mem_time_sum。NVTX 是额外的参考信息。 - 对于未插桩的元素,该技能会报告“此版本中无法直接测量”,并继续应用封闭形式的 R1–R6 参数(这些参数根据输入推导,而非依赖逐插件性能分析数据)。
- 此版本不包含为未插桩元素自动注入 NVTX 的功能——在最终报告中将其列为后续事项。
阶段 1 的输出:简短的覆盖情况表,例如:
nvurisrcbin COVERED
nvstreammux COVERED
nvinfer COVERED
nvtracker COVERED
queue_src UNINSTRUMENTED — not re-tuned
fakesink UNINSTRUMENTED — not re-tuned
阶段 2 — 硬件发现
运行 nvidia-smi,推导主机 GPU 的理论上限。最低查询要求:
# Identity + memory + compute
nvidia-smi --query-gpu=name,compute_cap,memory.total,memory.free,\
clocks.max.sm,clocks.max.memory,utilization.gpu \
--format=csv,noheader,nounits
# NVDEC / NVENC utilization (per-engine)
nvidia-smi --query-gpu=utilization.decoder,utilization.encoder \
--format=csv,noheader,nounits
# PCIe link width/gen (for H2D memcpy ceiling)
nvidia-smi --query-gpu=pcie.link.gen.current,pcie.link.width.current \
--format=csv,noheader,nounits
根据这些数据推导:
- 解码上限(fps):NVDEC_count × 源分辨率下每个单元的 H265/H264 fps (参见 references/hw-ceiling-formulas.md 中的表格)。
- 计算上限(TOPS):SM 数量 × 时钟频率 × 目标精度下每个时钟周期的运算数。这给出 一个上限——实际模型的性能可达到该值的 30–60%。
- 内存带宽上限(GB/s):内存时钟频率 × 总线位宽。模型权重读取和激活值应远低于此上限。
- Memcpy 上限(GB/s):PCIe 代际 × 通道数 × 0.8(实际值)。仅当 NVMM 出现故障,且第 5 阶段中出现 H2D/D2H 传输时才相关。
保存推导出的上限——它们将用于第 5 阶段的“实际值与理论值”部分。
完整公式和按编解码器分类的 NVDEC 吞吐量表: references/hw-ceiling-formulas.md。
阶段 3 — 仅推理微基准测试
仅运行推理阶段(source → streammux → nvinfer → fakesink),遍历
batch-size 以找到平台区间。这样可以从其他因素中隔离模型的真实峰值 FPS,并回答“一个批次中可容纳多少路流而不降低 FPS?”
遍历范围:batch-size ∈ {1, 2, 4, 8, 16, 32}(上限为 N_streams 和 GPU 内存容量)。
对于每个批次大小:
- 设置
nvstreammux.batch-size = nvinfer.batch-size = B。 - 设置
nvstreammux.width/height= 模型原生的infer-dims(从 nvinfer 配置中读取)。 - 将
fakesink sync=False设为唯一分支。 - 运行 30 s;从
measure_fps_probe(控制台)或 DSPerfMonitor测量 FPS。 - 记录
(B, fps)。
平台批次大小 = 最小的 B,使得增至 2×B 后 FPS 提升 < 5%。这就是完整流水线的目标批次大小。
如果用户的 N_streams ≤ 平台批次大小,则设置最终批次大小 = N_streams。否则设置最终 批次大小 = 平台批次大小,并注明流水线将在每个 tick 中分多个批次处理流。
阶段 4 — 推导配置
根据 (plateau_batch, HW_ceilings, N_streams, source_res, source_fps),一次性设置所有可调参数。不要一次只调一个参数——推导规则都有确定的解析形式。
按顺序设置以下参数:
- Streammux:
batch-size = final_batch,width/height = min(source_res, infer_dims),batched-push-timeout = 1e6 / source_fpsµs,nvbuf-memory-type = 0。 - 推理:
batch-size = final_batch,network-mode = 1 (INT8) if calib file exists else 2 (FP16),interval = 0,infer-dims = 模型原生维度,model-engine-file = 预构建的 .engine 路径。 - 解码器(在
nvurisrcbin/nvmultiurisrcbin/nvv4l2decoder上):num-extra-surfaces = min(final_batch, 5),cudadec-memtype = 0,nvbuf-memory-type = 0。 - 跟踪器(如有):
enable-batch-process = 1,跟踪器分辨率为 480×288,将ll-config-file指向config_tracker_NvDCF_max_perf.yml。 - 队列(如存在于解码器和 streammux 之间,或 streammux 和 nvinfer 之间):
max-size-buffers = final_batch × 2。Kafka/消息分支:leaky=2, max-size-buffers=2。
包含每条公式及一句“原因”说明的完整推导表: references/config-derivation-rules.md。
将推导出的值写入用户的配置文件(pgie_config.yml、
tracker_config.yml、pipeline.py 源属性,以及任何 deepstream-app .txt 文件)。
始终先 Read 再 Edit。只做必要的精确修改——不要重新格式化无关行。
阶段 5 — 端到端分析与报告
在 nsys profile 下运行端到端流水线,并通过 nsys stats 提取各插件的耗时。
采集:
TS=$(date +%Y%m%d_%H%M%S)
OUT=/tmp/ds_profile_${TS}
nsys profile \
--trace=cuda,nvtx,osrt \
--gpu-metrics-devices=all \
--cuda-memory-usage=true \
--force-overwrite=true \
--duration=30 \
--output=${OUT} \
<your-pipeline-launch-command>
提取:
# Per-kernel GPU time (top 10)
nsys stats --report cuda_gpu_kern_sum --format csv ${OUT}.nsys-rep | head -20
# Per-NVTX-range time (top 10) — this is the DS per-plugin breakdown
nsys stats --report nvtx_sum --format csv ${OUT}.nsys-rep | head -20
# Memcpy totals
nsys stats --report cuda_gpu_mem_time_sum --format csv ${OUT}.nsys-rep
# GPU metrics (SM activity, DRAM throughput) — requires --gpu-metrics-devices
nsys stats --report gpu_metric_gpu_util_sum --format csv ${OUT}.nsys-rep
完整命令参考:references/nsys-cli-recipes.md。
报告(Markdown,输出到 stdout——不使用外部 UI):
## Profile summary
**Hardware**: <name>, <mem_total> GB, SM x<sm>, NVDEC x<nvdec>, PCIe Gen<g> x<w>
**Ceilings**: decode <X> fps, compute ~<Y> TOPS @ INT8, memory <Z> GB/s
**Inference plateau**: batch=<B>, peak=<F> fps per batch → <F × B> fps aggregate
**E2E measured**: <actual> fps (=<pct>% of inference plateau)
### Per-plugin time (from NVTX) — only for plugins emitting NVTX in this build
| Plugin | Share of wall time | GPU / CPU | Notes |
|-----------------|--------------------|-----------|-------|
| nvinfer | <pct>% | GPU | (always emitted; if absent, NVTX injection is broken) |
| nvdsosd | <pct>% | GPU | (when in pipeline) |
| ... | ... | ... | (other plugins as the verification probe shows) |
(Numbers above are illustrative — fill in from `nsys stats --report nvtx_sum`. Plugins
that don't emit NVTX in your DS / image combo simply don't appear; that's not a bug, it's
the limit of what NVTX captures here. See `references/nvtx-coverage.md`.)
### Applied configs (sample shape; values come from R1–R6 + Stage 3 measurements)
- `nvstreammux.batch-size = <plateau_batch>`
- `nvinfer.network-mode = 1 (INT8)` if calibration available, else `2 (FP16)`
- decoder `num-extra-surfaces = min(plateau_batch, 5)`
- queue between source and pgie, `max-size-buffers = plateau_batch × 4`
- ... (full list per the user's pipeline shape)
### Uninstrumented (skipped re-tune)
List the elements that didn't emit NVTX in this build (typically the closed-source binary
plugins — see `references/nvtx-coverage.md`) plus plain GStreamer-core helpers. Report
them so the user knows what wasn't directly measurable.
摘要应简洁。原始 nsys stats CSV 写入临时文件,不要放在回复中。
参考文档
| 文档 | 适用场景 |
|---|---|
| references/nvtx-coverage.md | 阶段 1——将每个流水线元素分类为 COVERED 或 UNINSTRUMENTED。 |
| references/hw-ceiling-formulas.md | 阶段 2——将 nvidia-smi 输出转换为解码/计算/内存上限。 |
| references/config-derivation-rules.md | 阶段 4——按 (plateau_batch, HW, N_streams, source_res, source_fps) 索引的逐参数公式。 |
| references/nsys-cli-recipes.md | 阶段 3 和 5——精确的 nsys profile/nsys stats 调用命令。 |
非目标(此版本)
- 不使用 Nsight Lens/GUI。 仅使用终端。
- 不为未插桩的插件自动注入 NVTX。 MVP 会跳过这些插件的参数。后续版本再处理。
- 没有迭代式的调优—测量—调优循环。 阶段 4 根据闭式规则一次性推导配置;阶段 5 进行测量并报告结果。如果用户想继续调优,可以使用更新后的输入重新调用该技能。
相关技能
deepstream-generate-pipeline——上游流水线生成。此技能假设流水线已存在或即将生成。deepstream-byovm——HF → TensorRT 引擎构建。如果用户带来了新模型,请先运行此技能,再运行本技能。
备注
- 按照仓库
CLAUDE.md中的约定,此技能与其他 DS 技能一起位于skills/deepstream-profile-pipeline/。 - 要获取任何插件属性(类型、默认值、范围)和 Pad caps 的真实信息,请在 DS 容器内查询已加载的二进制文件:
插件命名约定:任何以gst-inspect-1.0 nvinfer gst-inspect-1.0 nvstreammux gst-inspect-1.0 nvurisrcbin # works on closed-source binary plugins too gst-inspect-1.0 | grep ^nv # list every NVIDIA-specific element this build shipsnv*为前缀的元素都是 NVIDIA DeepStream 专用元素(支持 NVMM,可能会发出 NVTX);其他所有元素都是上游 GStreamer-core(不支持 NVMM,绝不会发出 DS NVTX)。在排查陌生流水线时,将此前缀作为初步分类依据。 - 插件代码的开源子集位于
/opt/nvidia/deepstream/deepstream/sources/gst-plugins/下;如需阅读实现,可查看此处(只有部分插件开源;对于闭源插件,必须通过gst-inspect-1.0检查,并在运行时观察其行为)。