尧图精选

SGLang GPU 剖析实战:用 gputrc2graph 将 nsys 追踪文件转化为内核级耗时分析

🕒 发布时间:2026/9/11 1:46:10 📁 来源:尧图网络
SGLang GPU 剖析实战用 gputrc2graph 将 nsys 追踪文件转化为内核级耗时分析【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang本篇技术指南围绕 SGLang 仓库 examples/profiler/nsys_profile_tools 目录下的gputrc2graph.py展开讲解如何把 NVIDIA Nsight Systemsnsys采集的 CUDA GPU 追踪文件.nsys-rep转化为内核级别的耗时统计与可视化从而量化 GPU 与非 GPU 时间、按内核类别attention、gemm、moe 等定位性能瓶颈。读者学完后将能够独立完成 nsys 采集、单模型分析、多模型横向对比以及为新的引擎/模型扩展内核分类规则。工具定位从 nsys 原始追踪到内核级时间账单gputrc2graph.py是一个面向 SGLang 服务性能分析的后处理工具。它不负责采集数据而是消费nsys在-t cuda追踪模式下生成的.nsys-rep文件最终产出两类结果result.html内核名称按类别归并后的堆叠柱状图stacked bar chart直观展示各类别消耗的 GPU 秒数result.csv内核名称到类别的映射明细表供二次分析使用。从源码看脚本的核心工作链在 gputrc2graph.py 的gen_sum_file中完成它调用nsys stats -r cuda_gpu_trace导出内核追踪 CSV再通过gen_nonoverlapped_sum_from_gputrace计算非重叠non-overlappedGPU 耗时——即对按开始时间排序的内核区间做去重叠处理只累计真正独占 GPU 的时长避免多个流stream上并行内核被重复累加。这一口径是后续所有分析的基础。环境准备与依赖运行脚本前需要满足两个前提对应原文档 Notes 部分pandas任意版本均可脚本在GPUTrace2Graph.__init__中惰性导入见 gputrc2graph.py因此即使系统未预装 pandas也只需在分析机上pip install pandas即可。nsys 命令行工具需要已安装 NVIDIA Nsight Systems CLI并保证其版本不低于采集追踪时服务器端使用的 nsys 版本否则无法解析对应的.nsys-rep文件。若nsys不在系统 PATH 中用--nsys_cmd显式指定路径例如--nsys_cmd /usr/bin/nsys。关于 nsys 在 SGLang 环境下的安装与基本采集可参考 docs/docs/developer_guide/benchmark_and_profiling.mdx 中的 Profile with Nsight 章节其中提供了 apt 安装 nsight-systems-cli 的完整命令以及基于 SGLang Docker 容器的使用方式。命令行参数详解脚本通过 argparse 接收四个参数见 gputrc2graph.py参数必填说明--in_file是输入文件及其元数据列表每项格式为nsys-rep,engine,model,elapsed_nonprofiled_sec多项之间以空格分隔--out_dir否生成的 CSV 与 HTML 输出目录不指定则输出到当前目录--title否HTML 图表的标题不指定时默认使用Model_Engine--nsys_cmd否nsys命令路径默认nsys假设已在 PATH 中其中--in_file每个元组的四个字段含义如下nsys-rep.nsys-rep文件路径engine引擎名称例如sglang必须与引擎目录下的 JSON 文件定义一致model模型名称例如llama、gpt-oss、ds必须在该引擎下已注册elapsed_nonprofiled_sec未开启 profiling 时完成整个测试的墙钟运行时间秒。此值用于计算 CPU非 GPU耗时。若填0则退化为使用 nsys-rep 文件自身的记录时长——注意这可能虚增非 GPU 时间因为带 profiling 的实际运行时长往往更长。脚本在启动时会列出当前支持的所有engine:[model]组合并写入--help帮助字符串运行python3 gputrc2graph.py --help即可查看最新支持的引擎与模型清单这也是原文档推荐的首选排查方式。第一步用 nsys 采集 SGLang 服务的 CUDA 追踪以 llama-3.1-8B 模型 SGLang 服务为例完整流程分为四步步骤 1带 profiling 启动服务器nsys profile -t cuda -o nsys_res -f true --trace-fork-before-exectrue \ --cuda-graph-tracenode --delay DELAY --duration DURATION \ python3 -m sglang.launch_server --model meta-llama/Llama-3.1-8B ...-t cuda只追踪 CUDA 活动脚本仅依赖 cuda 追踪数据-o nsys_res输出文件前缀完成后生成nsys_res.nsys-rep-f true覆盖同名旧文件--trace-fork-before-exectrue追踪 fork/exec 产生的子进程确保多进程场景不丢失追踪段--cuda-graph-tracenode以节点粒度记录 CUDA Graph 内核SGLang 默认启用 CUDA Graph 加速必须开启此选项才能看到图内内核--delay DELAY延迟采集的秒数给足 SGLang 服务器加载模型、完成预热的时间避免采集到无意义的启动阶段--duration DURATION采集持续秒数必须大于客户端压测的总时长否则会截断负载阶段的追踪。若希望在服务器运行期间手动控制结束时机可以参考 benchmark_and_profiling.mdx 的做法先nsys sessions list获取会话 ID形如profile-XXXXX再nsys stop --sessionprofile-XXXXX立即停止 profiling 并生成.nsys-rep文件而无需等待--duration耗尽。步骤 2启动客户端负载服务器起来后另开终端运行 SGLang 的负载生成命令例如python3 -m sglang.bench_serving --backend sglang ...。测试完成后再过DURATION秒nsys 会生成nsys_res.nsys-rep并关闭服务器。步骤 3无 profiling 重跑一次负载重新按步骤 1 启动服务器这次不加nsys profile再按步骤 2 重跑客户端测试记录整个测试的完成秒数。这个未带 profiling 的真实墙钟时间是后续计算 CPU非 GPU耗时的基准。步骤 4运行分析脚本假如步骤 3 记录的总耗时为 132 秒python3 gputrc2graph.py \ --in_file run1.nsys-rep,sglang,llama,132脚本在当前目录生成result.html与result.csv两个文件也可用--out_dir指定输出目录。提示若当前目录下已存在同名的中间 CSV*_cuda_gpu_trace.csv、*_cuda_gpu_kernel_tracesum.csv脚本会根据修改时间判断是否复用缓存should_gen_file逻辑见 gputrc2graph.py重复分析同一份追踪时能明显提速。读懂 result.html堆叠柱状图与数据表result.html以堆叠柱状图展示各类别Category的 GPU 耗时秒数。以文档中的示例结果为例attention 内核类别耗时约 63 秒为最大类别其次为gemm内核。这种归并后的视图能让用户一眼定位时间花在哪从而确定性能优化时应优先投入的内核方向。柱状图下方还附加了一张数据透视表由make_html中的pivot_table生成见 gputrc2graph.py以 Category 为行、Model_Engine为列汇总耗时并在末尾追加total_elapsed_sec合计行方便直接复制到 Excel 或其他后处理工具中继续分析。读懂 result.csv从类别下钻到具体内核柱状图回答哪个类别耗时最多而result.csv回答这个类别里到底是哪些内核在消耗时间。它的每一行包含Model_Engine、Category、Instances、Name、Elapsed Time (sec)等字段记录了每个具体内核名称被映射到的类别。文档给出的场景非常典型假设用户想优化 triton 内核——它虽然不是最大的耗时来源例如仅 0.01 秒但可能从未被充分优化过。此时就可以从result.csv中筛选出Category triton_kernel的所有行找到具体是哪些 triton 内核、各自耗时多少、被调用多少次从而精准定位下一步的优化对象。csv 与 html 的映射口径完全一致同一份Category列因此可以放心交叉使用。多 profile 横向对比一次命令分析多份追踪当手头有多份不同模型或不同配置的 nsys 追踪文件时可以在一次调用中全部传入例如同时对比 llama 与 gpt-osspython3 gputrc2graph.py \ --in_file run1.nsys-rep,sglang,llama,100 run2.nsys-rep,sglang,gpt-oss,102 \ --out_dir results处理流程与单文件分析一致但输出中会出现多根堆叠柱可以直接比较不同模型/配置在各内核类别上的 GPU 耗时差异。由于所有追踪共用同一套类别定义跨配置的柱高对比是严格可比的。对比分析的典型用法是一旦发现某个类别在某配置下耗时显著偏高就用对应的result.csv查看该类别映射了哪些内核、哪几个内核耗时最大从而定位造成整体差异的根因内核。注意图表横轴标签会附加序号源码中df[Model_Engine] f{model}_{engine}_{file_name}_{idx}见 gputrc2graph.py当同一模型有多个副本时会自动区分。为新的引擎/模型扩展内核分类脚本的内核分类规则并非写死在代码里而是以 JSON 文件形式存放在 gputrc2graph.py同目录下。启动时load_engine_model会扫描该目录下所有*.json文件并合并见 gputrc2graph.py因此扩展新分类不需要改任何 Python 代码只需新增或修改 JSON 文件。仓库自带的引擎/模型定义位于 sglang_engine_model.json目前包含sglang引擎下的llama、dsDeepSeek、gpt-oss三个模型覆盖了 gemm、moe_gemm、moe、prepare_next、nccl_and_custom_ar、norm、topk、activation、rope、softmax、attn、elementwise、quantize、reduce、triton_kernel 等十余个类别。以文档中的例子假设要为引擎DEF、模型ABC建立分类且ABC有 4 个需要归类的内核——gemm 类内核名称含*H*或*I*attn 类内核名称含*J*或*K*则新建一个与gputrc2graph.py同目录的 JSON 文件例如engine_DEF.json内容如下{ DEF: { ABC: { H|I: gemm, J|K: attn, CUDA mem: non-gpu-H_D_memops, .*: misc } } }每个条目的含义key一个正则表达式regex用于匹配内核名称value匹配到的内核被归入的类别名。注意规则按 JSON 中声明的顺序依次匹配源码中anno_gpu_kernname_helper逐条re.search并返回首个命中项见 gputrc2graph.py因此越具体的规则应写在越前面。文件末尾的两条规则对所有引擎/模型通用建议保留CUDA mem: non-gpu-H_D_memops将 CUDA 内存操作memcpy/memset 等归为非 GPU 计算类.*: misc兜底规则匹配一切剩余未分类的内核保证每个内核都能被归类、不会出现空类别。保存 JSON 后直接按新引擎/模型运行脚本即可--in_file new.nsys-rep,DEF,ABC,runtime如果engine_DEF.json文件已存在只需在该引擎节点下追加一个新模型节点即可无需重建文件脚本会自动把同一引擎下所有模型的定义合并到内存中。源码要点非重叠耗时如何计算理解Elapsed Time (sec)与Total Time (sec)的区别是正确解读结果的前提。两者的差异源自 sum_non_overlapping_intervals先把所有内核按Start (ns)升序排序用current_end维护当前已覆盖区间的最大结束时间对每个后续内核若其开始时间落在已覆盖区间内部分重叠只累加超出current_end的新增时长并推进current_end完全重叠耗时记为 0无重叠完整计入并推进current_end。这样得到的是每个内核在 GPU 上独占的有效耗时。CSV 中的Elapsed Time (sec)即基于此口径而Total Time (sec)是内核自身的原始Duration累加。前者用于堆叠图与类别汇总后者反映原始调用总量两者结合可以判断并行度的高低。此外非 GPUCPU耗时在gen_graph中通过total_sec - gpu_sec计算见 gputrc2graph.py并追加为一行Category CPU(non-GPU)的虚拟记录若传入的elapsed_nonprofiled_sec反而小于 GPU 耗时数据异常脚本会告警并将总耗时重置为 GPU 耗时避免出现负的 CPU 时间。常见问题与排查报错nsys failed ... Use --nsys_cmd to specify nsys pathnsys不在 PATH 中或命令执行失败。用--nsys_cmd传入完整路径同时确认本地 nsys 版本 ≥ 采集追踪时的版本见 gputrc2graph.py。报错engine X unknown/model Y unknown--in_file中填写的引擎/模型名未在 JSON 中注册。运行python3 gputrc2graph.py --help查看支持的engine:[model]列表并按上一节方式扩展 JSON。CPU(non-GPU) 时间异常偏大检查elapsed_nonprofiled_sec是否填了带 profiling 的时长或填了 0。文档明确提示填0会使用 nsys-rep 文件内的记录时长可能虚增非 GPU 时间应填写未带 profiling时的真实墙钟运行秒数。看不到 CUDA Graph 内的内核采集时务必带上--cuda-graph-tracenode否则图捕获后的内核不会出现在追踪中导致类别耗时严重失真。小结gputrc2graph.py把 SGLang nsys 的 GPU 剖析流程收敛为采集 → 一行命令分析 → 堆叠图 映射表的闭环result.html回答时间花在哪个类别result.csv回答该类别下具体是哪些内核JSON 规则文件则让内核分类可以随新引擎/新模型零代码扩展。结合 sglang_engine_model.json 中现成的 llama、ds、gpt-oss 分类定义SGLang 使用者可以快速将性能优化从凭经验猜测推进到按内核耗时数据决策。【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →