Prhub

#38366 [BugFix][CPU] Add CPU profiler summary file output

原始 PR 作者 Elm8116 合并时间 2026-04-10 13:41 文件变更 1 提交数 8 评论 13 代码增减 +33 / -15

执行摘要

修复 CPU 性能分析器缺失摘要文件输出,确保与 CUDA 行为一致。

修复 issue #38131 中报告的问题:当在 CPU 后端使用 torch profiler 时,torch_profiler_dump_cuda_time_total 标志在内部被禁用,且没有等效的 CPU 摘要文件被写入,开发者只能通过日志查看 self_cpu_time_total,这导致了“CPU 性能分析器摘要文件静默缺失”的问题。PR 描述明确指出,此变更旨在“改善 CPU 和 GPU 性能分析之间的一致性,并避免在 CPU 上静默丢失性能分析器输出”。

该 PR 值得负责性能分析工具链或 CPU 后端的工程师精读,因为它展示了如何通过提取辅助函数来统一跨后端的输出行为,并处理了 API 兼容性细节。关注点包括:

1) _build_profiler_table 中对 row_limit 参数的条件传递设计;
2) _write_profiler_table 中 URI 路径检查的逻辑复用;
3) review 中关于“打印在 rank 0,文件写入在所有 rank”的设计决策及其一致性考量。

讨论亮点

Review 中的核心讨论包括:

1) 设计权衡:fadara01 最初建议在 if self.dump_cpu_time_total and rank == 0: 条件下提取公共函数,但 bigPYJ1151 指出应使 CPU 行为与 CUDA 一致,即“在 rank 0 上打印,在所有 rank 上写入文件”。最终采纳了后者的建议,确保跨后端的一致性。
2) API 兼容性:bigPYJ1151 指出 row_limit=None 可能与 PyTorch Profiler 的 table() 方法不兼容(引用 PyTorch 源代码行)。作者随后更新了 _build_profiler_table,仅在 row_limit 非 None 时传递该参数,避免了潜在错误。
3) 代码冗余检查:fadara01 询问 if row_limit is None: 判断是否冗余,但此判断在最终代码中仍被保留,以正确处理默认行为。讨论最终达成共识,PR 在解决这些疑虑后获得批准。

实现拆解

修改集中在 vllm/profiler/wrapper.pyTorchProfilerWrapper 类中。主要改动包括:

1) 新增 _build_profiler_table 辅助函数,封装对 profiler.key_averages().table() 的调用,支持指定排序键(sort_key)和可选的 row_limit 参数;
2) 新增 _write_profiler_table 辅助函数,封装文件写入逻辑,检查 URI 路径并生成 profiler_out_<rank>.txt 文件;
3) 在 _stop 方法中,重构 CUDA 和 CPU 的摘要输出逻辑:对于 CUDA 路径(当 torch_profiler_dump_cuda_time_total 为真时)和 CPU 路径(当 dump_cpu_time_total 为真时),均调用上述辅助函数来生成表格并写入文件,且仅当 rank == 0 时才打印表格到日志,确保文件写入在所有 rank 上进行以避免数据丢失,但日志输出仅限 rank 0 以防止冗余。这消除了原始实现中 CPU 路径缺少文件写入的问题。

文件 模块 状态 重要度
vllm/profiler/wrapper.py profiler modified 9.0

关键符号

_build_profiler_table _write_profiler_table _stop

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

CPU 与 CUDA profiler 输出行为的一致性设计 设计

bigPYJ1151 建议 CPU profiler 应匹配 CUDA 行为,即打印在 rank 0,但在所有 rank 上写入文件,而非仅限 rank 0 处理。

结论:作者采纳建议,更新代码以确保一致性,统一了文件写入和日志打印的逻辑。 · 已解决

PyTorch Profiler API 中 row_limit 参数的兼容性处理 正确性

bigPYJ1151 指出 row_limit=None 可能不兼容 PyTorch Profiler 的 table() 方法,并引用源码行佐证。

结论:作者更新 _build_profiler_table,仅在 row_limit 非 None 时传递该参数,避免潜在错误。 · 已解决

代码中 if row_limit is None: 判断是否冗余 style

fadara01 询问此判断是否多余,暗示可能简化代码。

结论:判断在最终代码中保留,以确保默认行为(row_limit=None 时使用 profiler 默认限制)正确;未进一步讨论简化。 · partially_resolved

风险与影响

技术风险较低:

1) 回归风险:CUDA 路径的行为未改变,仅重构为使用新辅助函数,逻辑等价;CPU 路径新增文件写入,但受 dump_cpu_time_total 标志控制(默认可能为 False,需检查配置),且写入前检查 URI 路径,不会破坏现有流程。主要风险是文件 I/O 可能在分布式环境下引入轻微性能开销,但通过仅限 rank 0 打印日志和合理的文件写入策略得以缓解。
2) 兼容性风险:对 row_limit 参数的处理调整确保了与 PyTorch Profiler API 的兼容性。
3) 测试覆盖:PR 提供了手动测试方案,但未提及自动化测试的更新;这可能意味着测试覆盖不完全,但鉴于变更范围小且聚焦于工具输出,风险可控。

1) 用户影响:对使用 CPU 后端进行性能分析的开发者,现在可以获得与 CUDA 一致的、可读的摘要文件输出(profiler_out_<rank>.txt),提升了调试和优化体验;用户需注意文件仅在非 URI 路径下生成。
2) 系统影响:性能分析器工具链更加完善,CPU 和 GPU 路径的行为对齐,减少了特殊 case 处理。
3) 团队影响:代码经过重构更清晰(提取辅助函数),增强了可维护性;变更局限于单个文件,不影响核心推理逻辑。影响范围中等,主要涉及开发工具层面。

分布式文件 I/O 开销 缺少自动化测试

关联 Issue

#38131 [Bug]: [CPU Backend] No CPU profiler summary equivalent; CUDA summary flag is silently disabled on CPU

完整报告

参与讨论