ワンクリックで
nsys-capture
通用 GPU 推理服务 nsys 性能抓取工具。根据用户的启动脚本自动注入 nsys 命令、构建带 nsys 的启动脚本,完成完整的 GPU profiling 抓取流程,输出 .nsys-rep 文件。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
通用 GPU 推理服务 nsys 性能抓取工具。根据用户的启动脚本自动注入 nsys 命令、构建带 nsys 的启动脚本,完成完整的 GPU profiling 抓取流程,输出 .nsys-rep 文件。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | nsys-capture |
| description | 通用 GPU 推理服务 nsys 性能抓取工具。根据用户的启动脚本自动注入 nsys 命令、构建带 nsys 的启动脚本,完成完整的 GPU profiling 抓取流程,输出 .nsys-rep 文件。 |
Step 1:信息收集 → 从用户脚本和描述中提取关键参数
Step 2:注入 profiling → 检查并向 FastDeploy 代码注入 nvprof_start/nvprof_stop
Step 3:生成脚本 → 构建 start_nsys.sh(注入 nsys)+ 确认请求脚本
Step 4:用户确认 → 展示生成的脚本,等用户确认后才执行
Step 5:执行抓取 → 启动服务 → 等待就绪 → 发送请求 → 等待文件 → 重命名
读取用户提供的启动脚本,提取以下信息:
| 信息 | 提取方式 | 无法提取时 |
|---|---|---|
| 模型路径 | --model 参数 / MODEL_PATH 变量 / 用户描述 | 询问用户,必填 |
| 服务端口 | --port / --ports 参数 / 用户描述 | 询问用户,默认 8080 |
| Host IP | 用户描述("本机"→127.0.0.1,远端则询问) | 默认 127.0.0.1 |
| nsys 输出目录 | 用户描述 / 脚本中 OUTPUT_DIR、NSYS_PATH 变量 | 默认 /tmp/nsys_record |
| nsys 版本 | 用户指定("详细版"/"高版" or "粗略版"/"低版") | 默认粗略版 |
| 请求脚本 | 用户是否提供了测试请求脚本 | 使用 skill 内置默认脚本 |
| nsys_start_step | 用户指定 nvprof_start 触发的 decode 步数 | 默认 40 |
| nsys_stop_step | 用户指定 nvprof_stop 触发的 decode 步数 | 默认 60 |
信息收集完毕后,进入 Step 2。
nsys 使用 -c cudaProfilerApi 模式,要求 FastDeploy 代码中必须包含 nvprof_start() / nvprof_stop() 调用。本步骤自动检测并注入。
按优先级查找目标文件 fastdeploy/worker/gpu_model_runner.py:
PYTHONPATH 或 sys.path 指定了 FastDeploy 路径(如 export PYTHONPATH=/path/to/FastDeploy:$PYTHONPATH),若有,使用该路径下的 fastdeploy/worker/gpu_model_runner.pypip3 show fastdeploy-gpu,取 Location 字段,拼接 fastdeploy/worker/gpu_model_runner.py确认文件存在后继续。若文件不存在,提示用户手动指定路径。
在 gpu_model_runner.py 中搜索 nvprof_start 和 nvprof_stop:
grep -n "nvprof_start\|nvprof_stop" <path_to_gpu_model_runner.py>
if False 守卫、代码未注释)→ 跳过注入,提示用户已有 profiling 代码,直接进入 Step 3if False 守卫或被注释)→ 提示用户发现已有但被禁用的 profiling 代码,询问是否需要启用并修正 step 值注入前先备份原文件:
cp <path_to_gpu_model_runner.py> <path_to_gpu_model_runner.py>.bak
需注入 3 处代码,参考模板来自 fastdeploy/worker/gpu_model_runner.py 的已有实现模式:
__init__ 方法中在 self.current_launch_token_num = 0 之后添加:
self.nsys_step = 0
_execute_model 方法中,执行调度代码之前找到如下执行调度代码块:
if not self.enable_overlap_schedule:
self.execute_model_normal(model_forward_batch, num_running_requests)
else:
self.execute_model_overlap(model_forward_batch, num_running_requests)
在其之前插入 nvprof_start:
if self.nsys_step == <nsys_start_step> and self.forward_meta.ids_remove_padding.shape[0] > 0:
from paddle.framework import core
core.nvprof_start()
<nsys_start_step>替换为 Step 1 收集到的值,默认 40。
_execute_model 方法中,执行调度代码之后在执行调度代码块之后插入 nvprof_stop 和步数递增:
if self.nsys_step == <nsys_stop_step> and self.forward_meta.ids_remove_padding.shape[0] > 0:
from paddle.framework import core
core.nvprof_stop()
if self.forward_meta.ids_remove_padding.shape[0] > 0:
self.nsys_step += 1
<nsys_stop_step>替换为 Step 1 收集到的值,默认 60。
注入完成后,向用户展示修改的 diff:
diff <path_to_gpu_model_runner.py>.bak <path_to_gpu_model_runner.py>
说明:
<nsys_start_step> 步触发,nvprof_stop 在第 <nsys_stop_step> 步触发.bak等用户确认后,进入 Step 3。
不要 使用 nsys profile ... bash start.sh 的包裹形式。
要 在脚本内部,找到实际启动服务的可执行命令行(python / python3 / torchrun / deepspeed 等),在该行前面直接插入 ${NSYS_CMD},让 nsys 成为该进程的直接父进程。
# 原始脚本中的启动命令:
python -m some.serving.module \
--model /path/to/model \
--port 8080
# 注入后:
${NSYS_CMD} python -m some.serving.module \
--model /path/to/model \
--port 8080
#!/bin/bash)之后、其他内容之前,插入 nsys 变量定义块(见 3.3)python / python3 命令,在行首插入 ${NSYS_CMD}
\ 续行),只在第一行行首加 ${NSYS_CMD},续行不动_nsys 后缀,如 start.sh → start_nsys.sh# ============================================================
# NSYS INJECTION - 由 nsys-capture skill 自动注入
# ============================================================
NSYS_OUTPUT_DIR="${NSYS_OUTPUT_DIR:-/tmp/nsys_record}"
mkdir -p "${NSYS_OUTPUT_DIR}"
NSYS_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
NSYS_OUTPUT_PATH="${NSYS_OUTPUT_DIR}/${NSYS_TIMESTAMP}_nsys"
echo "${NSYS_OUTPUT_PATH}" > /tmp/nsys_capture_output_path
echo "[nsys-capture] nsys 输出路径: ${NSYS_OUTPUT_PATH}"
然后根据用户选择的版本,追加对应的 NSYS_CMD 定义(两版都写,未选中的注释掉):
粗略版(默认,日常性能分析,文件约 6-15 MB):
# 粗略版(已启用)
NSYS_CMD="nsys profile -c cudaProfilerApi \
-t nvtx,osrt,cuda,cublas-verbose,python-gil \
-f true \
--cudabacktrace=all \
--python-backtrace=cuda \
--cuda-memory-usage=true \
--output ${NSYS_OUTPUT_PATH}"
# 详细版(深度调试,含完整 cuda graph trace,文件可达数百 MB)
# NSYS_CMD="nsys profile -c cudaProfilerApi \
# -t nvtx,osrt,cuda,cublas-verbose,python-gil \
# -f true \
# --cudabacktrace=all \
# --python-backtrace=cuda \
# --cuda-memory-usage=true \
# --cuda-graph-trace=node \
# --output ${NSYS_OUTPUT_PATH}"
详细版(用户指定时):将上面两段注释状态互换即可。
# 粗略版(日常性能分析,文件约 6-15 MB)
# NSYS_CMD="nsys profile -c cudaProfilerApi \
# -t nvtx,osrt,cuda,cublas-verbose,python-gil \
# -f true \
# --cudabacktrace=all \
# --python-backtrace=cuda \
# --cuda-memory-usage=true \
# --output ${NSYS_OUTPUT_PATH}"
# 详细版(已启用)
NSYS_CMD="nsys profile -c cudaProfilerApi \
-t nvtx,osrt,cuda,cublas-verbose,python-gil \
-f true \
--cudabacktrace=all \
--python-backtrace=cuda \
--cuda-memory-usage=true \
--cuda-graph-trace=node \
--output ${NSYS_OUTPUT_PATH}"
注意:
NSYS_OUTPUT_PATH在定义NSYS_CMD时已展开,所以两个块的顺序必须是:先定义NSYS_OUTPUT_PATH,再定义NSYS_CMD。 如果用户脚本中NSYS_OUTPUT_DIR已有定义,注入块中的默认值会被覆盖,以用户脚本的为准。
/data/nsys/),将注入块中的默认值替换为该路径:
NSYS_OUTPUT_DIR="/data/nsys/"
NSYS_OUTPUT_DIR 或类似变量,注入块放在该变量之后,并删除默认值赋值,直接复用。向用户展示生成好的 start_nsys.sh 关键内容(注入块 + 被注入的 python 命令行),说明:
等用户确认后,进入 Step 5 执行。
请求脚本优先级:
python3 ~/.claude/skills/nsys-capture/nsys_default_client.py <HOST> <PORT>
rm -f /tmp/nsys_serve.log
bash <path_to_start_nsys.sh> > /tmp/nsys_serve.log 2>&1 &
echo "服务启动中,PID=$!"
轮询策略(每 30s 一次):
curl -s http://<HOST>:<PORT>/v1/models 返回 HTTP 200Traceback / AssertionError / OOM / Killed,且 30s 内日志无新增行 → 停止等待,输出最后 30 行日志供排查检查日志时,每次只取最新 50 行(避免进度条等刷屏内容干扰):
tail -50 /tmp/nsys_serve.log | grep -E "Traceback|AssertionError|OOM|Killed|startup complete"
python3 <request_script> [HOST] [PORT] 2>/dev/null || true
RemoteProtocolError)是正常现象,不报错NSYS_OUTPUT_BASE=$(cat /tmp/nsys_capture_output_path)
EXPECTED_FILE="${NSYS_OUTPUT_BASE}.nsys-rep"
轮询直到文件出现且大小稳定(连续两次 stat -c%s 相同,间隔 3s),超时 120s。
稳定后重命名(带类型标记):
FINAL_NAME="${NSYS_OUTPUT_DIR}/$(date +%Y%m%d_%H%M%S)_nsys_<type>_<level>.nsys-rep"
# type: text(文生文)/ mm(多模态)/ custom(用户自定义请求)
# level: low(粗略版)/ high(详细版)
mv "${EXPECTED_FILE}" "${FINAL_NAME}"
输出最终路径和文件大小,抓取完成。
| 版本 | 额外参数 | 文件大小 | 适用场景 |
|---|---|---|---|
| 粗略版(默认) | 无 --cuda-graph-trace | 6-15 MB | 日常性能分析,快速查看算子耗时 |
| 详细版 | --cuda-graph-trace=node | 可达数百 MB | 深度调试,完整 cuda graph 节点信息 |
Q: nsys 文件未生成?
nvprof_start 和 nvprof_stop 各一处,顺序正确nsys sessions list 查看是否进入过 RangeCollection 状态Q: 服务启动失败?
/tmp/nsys_serve.log 最后 50 行Q: 如何分析 .nsys-rep 文件?
nsys-ui <file>.nsys-rep
Q: 需要抓多次怎么办?
每次抓取后服务会自动退出(nvprof_stop 触发),下次需重新启动(需重新加载模型)。