mcpField
P
pt2-bug-basher

pt2-bug-basher

github.com/pytorch开发105.2k143 次安装今天更新
代码仓库

关于 pt2-bug-basher

面向 PyTorch 开发者的调试技能,覆盖 Dynamo、Inductor、AOTAutograd 和 FX 图中的编译故障。它按环境检查、最小化复现、测试、诊断和验证的步骤引导排查。

主要功能

  1. 01检查 conda 环境和 PyTorch 导入
  2. 02复现并精简故障案例
  3. 03代码调查前添加回归测试
  4. 04分类错误并收集编译产物
  5. 05指导根因分析与测试验证

适用场景

  1. 01排查 torch.compile 图中断
  2. 02将 Inductor 故障缩减为最小案例
  3. 03诊断编译模型的数值不匹配

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pytorch/pytorch --skill pt2-bug-basher

安装后在 Claude Code 中输入/pt2-bug-basher确认已加载。

详细介绍

PT2 Bug Basher

调试 PyTorch 2 编译器栈(Dynamo、Inductor、AOTAutograd、FX 图)中的测试失败和运行时错误。

工作流摘要

  1. 检查环境 -- 询问用户要使用哪个 conda 环境。检查 $CONDA_DEFAULT_ENV,确认该环境已激活。然后运行 python -c "import torch; print(torch.__version__)",确认可以导入 torch,并报告其版本。如果环境未激活或无法导入 torch,请停止操作,并让用户先激活正确的环境。
  2. 复现 -- 稳定地复现故障
  3. 缩减 -- 将复现用例缩减为尽可能小的独立案例。移除无关的模型逻辑,使用最小张量形状,并隔离触发 Bug 的具体算子或模式。
  4. 添加单元测试 -- 在深入搜索代码或调查根因之前,先完成此步骤。 在代码库中添加一个能捕获该 Bug 的失败测试。将其放在具体且符合主题的测试文件中(例如,test/dynamo/test_repros.py、test/inductor/test_torchinductor.py、test/export/test_export.py)。避免使用 test/dynamo/test_misc.py——该文件已经过于庞大;请找到与 Bug 所属领域匹配的、更具体的测试文件。使用 torch.testing._internal.common_utils.TestCase 和 run_tests。修复前测试必须失败,修复后必须通过。先写测试能让你始终保持目标明确——在开始探索代码库之前,你就能清楚地知道“修复完成”是什么样子。
  5. 在 main 上验证 -- 使用 EnterWorktree 创建一个检出到 main 的工作树。将新测试文件复制到该工作树中,并在那里运行测试,确认它在 main 上失败。如果测试在 main 上通过,请停止——测试可能没有捕获到正确的 Bug,或者 Bug 可能已经修复。使用 ExitWorktree(action: remove)退出工作树,并返回工作分支后再继续。
  6. 收集日志 -- 使用合适的 TORCH_LOGS 设置运行
  7. 分类 -- 使用 错误分类 表确定类别
  8. 检查产物 -- 通过 TORCH_COMPILE_DEBUG=1 检查 FX 图、IR 和生成的代码
  9. 找出根因 -- 从错误出发,沿编译流水线追溯
  10. 修复 -- 应用修复
  11. 验证 -- 运行新增的单元测试以及附近相关的现有测试(例如,如果你更改了 is_exporting 的行为,也要运行现有的 test_is_exporting export 测试)。使用 pytest -k 按名称快速运行相关测试。所有测试通过后,任务才算完成。
  12. 自我审查 -- 在提交更改前,使用 /pr-review 技能审查自己的修改。修复它指出的所有问题。
  13. 庆祝 -- 总结更改:解释根因、修改了什么以及原因,并说明新增和验证了哪些测试。然后告诉用户 Bug 已解决。添加一句有趣、多样的鼓励语或彩蛋(例如双关语、引言,或 Bug 被拍扁的 ASCII 艺术图)。简短一些,每次都换个说法。

调查策略

优先使用直接工具,而非 meta_codesearch

直接使用 Grep、Glob 和 Read 探索代码。不要启动 meta_codesearch Agent——它们速度慢且成本高。下面的架构知识和关键源文件部分应能提供足够背景,帮助你确定查找方向。针对函数名执行定向 Grep 总是更快。

确认当前所处的编译模式

在阅读实现代码之前,先确定编译模式。这些模式会共用代码,但在重要方面有所不同:

  • torch.compile——Dynamo + Inductor。tx.export=False,不会激活 _compiling_state_context()。
  • torch.export(严格模式)——tx.export=True,_compiling_state_context() 处于激活状态。
  • torch.export(非严格模式,默认)——通过 fullgraph_capture 使用 Dynamo,但 tx.export 可能与严格模式不同。_compiling_state_context() 处于激活状态。检查 torch._export.config.use_new_tracer_experimental——它会改变所使用的代码路径。
区分跟踪时与运行时

许多 PT2 错误都源于混淆这两者:

  • 跟踪时:在 Dynamo 的符号解释器内部。Dynamo 会拦截函数调用,并可能将其常量折叠(例如,is_exporting() → ConstantVariable(True))。
  • 运行时:真实张量、真实 Python 调用,以及 torch.compiler._is_exporting_flag 这类模块级标志。

调试时,直接在源文件中临时添加 print() 语句,而不是从外部进行猴子补丁——分发链会使猴子补丁不可靠。

收集信息

根据错误类别选择合适的诊断工具:

  • 快速概览:TORCH_LOGS="+dynamo,graph_breaks,recompiles" python your_script.py
  • 完整调试产物:TORCH_COMPILE_DEBUG=1 python your_script.py——会创建包含 FX 图、Inductor IR 和生成代码的 torch_compile_debug/
  • 仅生成代码:TORCH_LOGS="output_code" python your_script.py
  • 结构化跟踪:先运行 TORCH_TRACE=/path/to/trace python your_script.py,然后运行 tlparse /path/to/trace
  • 单线程运行(用于 pdb):TORCHINDUCTOR_COMPILE_THREADS=1 python your_script.py

错误分类

根据错误消息和回溯对故障进行分类:

错误模式类别跳转到
日志中出现 Unsupported: ... 或 graph break图中断图中断
BackendCompilerFailedInductor/后端崩溃后端编译器故障
RecompileError 或 cache_size_limit重新编译重新编译问题
精度不匹配 / 数值输出错误精度精度问题
InternalTorchDynamoErrorDynamo 错误内部错误
段错误或 CUDA IMA运行时崩溃运行时崩溃
Triton 断言 / 索引越界Triton 内核错误Triton 故障

按类别调试

图中断

图中断会将编译后的图拆分为更小的子图,常常导致性能下降或行为异常。

诊断:

TORCH_LOGS="graph_breaks" python your_script.py

关键文件:

  • torch/_dynamo/exc.py——Unsupported 异常类
  • torch/_dynamo/variables/——大多数图中断决策发生的位置

常见原因:

  • 不受支持的 Python 结构(依赖数据的控制流、不受支持的内置函数)
  • 无法跟踪的张量操作(对输入执行原地操作、不受支持的数据类型)
  • 调用无法跟踪的函数

修复方法:

  1. 阅读图中断消息,找出不受支持的操作
  2. 检查是否存在分解实现或受支持的替代方案
  3. 如果该操作确实无法跟踪,可考虑使用 torch._dynamo.allow_in_graph 或重构用户代码
后端编译器故障

BackendCompilerFailed 表示 Inductor(或其他后端)在编译期间崩溃。

诊断:

TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=2 python your_script.py

这会生成 minifier_launcher.py,用于隔离出最小的故障图。

关键文件:

  • torch/_dynamo/repro/after_aot.py -- 用于 AOT 后故障的复现/缩减器
  • torch/_inductor/ -- 后端本身

修复方法:

  1. 运行缩减器,获得最小复现
  2. 检查 FX 图(TORCH_COMPILE_DEBUG=1),了解涉及哪些算子
  3. 检查问题是否出在降级(torch/_inductor/lowering.py)、调度或代码生成
  4. 如果错误出在代码生成阶段,查看生成的输出代码
重新编译问题

当守卫条件过于具体,导致缓存未命中时,就会发生过度重新编译。

诊断:

TORCH_LOGS="recompiles,recompiles_verbose,guards" python your_script.py

关键配置:

  • torch._dynamo.config.recompile_limit(默认值:8)
  • torch._dynamo.config.fail_on_recompile_limit_hit -- 设为 True 可在达到限制时触发硬错误

常见原因:

  • 更改张量形状,却未将其标记为动态
  • 多次调用之间发生变化的 Python 标量值
  • 调用之间的全局状态发生变化

修复方法:

  1. 从日志中读取重新编译的原因
  2. 找出未通过的守卫
  3. 使用 torch._dynamo.mark_dynamic() 将相关维度标记为动态,或修复导致守卫不稳定的根源
精度问题

编译后的模型与急切模式产生的数值结果不同。

诊断:

TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=4 python your_script.py

这会使用 fp64 参考结果比较编译模式与急切模式,并在精度检查失败时转储复现文件。

关键工具:

  • torch/_dynamo/debug_utils.py -- same_two_models()、backend_accuracy_fails()、cast_to_fp64()
  • torch._dynamo.config.repro_tolerance(默认值:1e-3)

修复方法:

  1. 从缩减器获取最小故障图
  2. 以 fp64 精度比较急切模式与编译模式的输出
  3. 对算子进行二分查找,找出结果开始偏离的算子
  4. 检查已知的数值问题(归约顺序、融合内核、数据类型提升)
Dynamo 内部错误

InternalTorchDynamoError 表示 Dynamo 本身存在错误。

诊断:

TORCHDYNAMO_VERBOSE=1 python your_script.py
# or equivalently:
TORCH_LOGS="+dynamo" python your_script.py

关键文件:

  • torch/_dynamo/symbolic_convert.py -- 字节码解释器
  • torch/_dynamo/variables/ -- 变量跟踪系统
  • torch/_dynamo/guards.py -- 守卫生成

修复方法:

  1. 使用 TORCHDYNAMO_VERBOSE=1 获取完整堆栈跟踪
  2. 找出导致崩溃的字节码指令或变量类型
  3. 创建最小复现(错误消息通常会包含缩减器路径)
  4. 如有需要,使用 TORCHINDUCTOR_COMPILE_THREADS=1 和 pdb 进行调试
运行时崩溃

执行编译后的代码时发生段错误和 CUDA 非法内存访问错误。

诊断(使崩溃变得可复现):

PYTORCH_NO_CUDA_MEMORY_CACHING=1 CUDA_LAUNCH_BLOCKING=1 python your_script.py

对于 CUDA IMA,添加 NaN 检查:

TORCHINDUCTOR_NAN_ASSERTS=1 python your_script.py

对于 Inductor 级别的同步调试:

torch._inductor.config.triton.debug_sync_kernel = True  # sync after every kernel
torch._inductor.config.triton.debug_sync_graph = True   # sync before/after graph

修复方法:

  1. 使用 PYTORCH_NO_CUDA_MEMORY_CACHING=1 CUDA_LAUNCH_BLOCKING=1 使崩溃变得可复现
  2. 检查是否存在输入不匹配(形状、设备、数据类型)
  3. 使用 TORCH_LOGS="output_code" 检查生成的内核代码
  4. 使用 TORCHINDUCTOR_NAN_ASSERTS=1 找出第一个产生错误值的内核
  5. 检查动态形状问题(历史上这是 IMA 的常见来源)
Triton 内核故障

Triton 断言失败,或生成的内核中出现索引越界。

诊断:

TORCH_LOGS="output_code,schedule" python your_script.py

关键文件:

  • torch/_inductor/codegen/triton.py -- Triton 代码生成
  • torch/_inductor/scheduler.py -- 内核融合决策

修复方法:

  1. 从 output_code 日志中获取生成的 Triton 内核
  2. 检查索引计算是否存在差一错误或错误的步长计算
  3. 查看 IR(TORCH_COMPILE_DEBUG=1),追溯到对应的 FX 算子
  4. 检查融合决策是否产生了无效的索引组合

关键源文件

文件用途
torch/_dynamo/exc.py异常层级结构与错误格式化
torch/_dynamo/debug_utils.py缩减器支持、准确性检查、输入序列化
torch/_dynamo/repro/after_dynamo.py用于 Dynamo 阶段故障的复现/缩减器
torch/_dynamo/repro/after_aot.py用于 AOTAutograd 后故障的复现/缩减器
torch/_dynamo/repro/aoti.py用于 AOTI 故障的复现/缩减器
torch/_dynamo/config.pyDynamo 配置(复现级别、重新编译限制)
torch/_dynamo/variables/torch.pyTorch 函数处理、跟踪状态函数
torch/_dynamo/variables/higher_order_ops.pyHOP 跟踪(cond、map 等)
torch/_dynamo/symbolic_convert.py字节码解释器、InstructionTranslator
torch/_dynamo/convert_frame.py帧编译、fullgraph_capture 入口
torch/_dynamo/functional_export.py新的导出跟踪器(_dynamo_graph_capture_for_export)
torch/_dynamo/eval_frame.pytorch._dynamo.export、optimize_assert
torch/_export/_trace.py导出流水线(_export、_strict_export、_non_strict_export、_export_to_aten_ir)
torch/_export/utils.py_compiling_state_context()
torch/compiler/__init__.pyis_compiling()、is_exporting()、运行时标志
torch/_higher_order_ops/cond.pytorch.cond 实现与代理跟踪
torch/_higher_order_ops/utils.py用于 HOP 分支跟踪的 reenter_make_fx
torch/_inductor/config.pyInductor 配置(调试标志、跟踪设置)
torch/_inductor/debug.pyDebugContext、图可视化、IR 日志记录
torch/_logging/_registrations.py所有已注册的日志别名和产物

使用缩减器

缩减器会将失败的图缩减为最小复现:

# Step 1: Generate the minifier launcher
TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=2 python your_script.py

# Step 2: Run the minifier
python minifier_launcher.py minify

# Step 3: Run the minimized repro
python minifier_launcher.py run

对于准确性问题,请使用级别 4:

TORCHDYNAMO_REPRO_AFTER=aot TORCHDYNAMO_REPRO_LEVEL=4 python your_script.py

评论

支持 Markdown