调试指南:从可复现定位到中间值排查)
PyTorch AOTInductor CUDA 非法内存访问IMA调试指南从可复现定位到中间值排查【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorchAOT Inductor 是 PyTorch 2.x PT2 技术栈中面向 C 部署环境的编译后端它与torch.compile共享同一套 Inductor 代码生成逻辑但产出的是可直接在纯 C 环境中链接加载的编译产物。当你在使用 AOT Inductor 时遇到CUDA illegal memory accessIMA错误——这类错误常以非确定性、时隐时现的方式出现甚至有时程序正常退出但数值早已悄悄出错——本指南提供了从基础健全性检查到逐 kernel 中间值审查的系统化排查路径。读完本文你将掌握 AOTI 调试中三个关键环境变量组合的用法、可复现 IMA 的确定性触发手段以及利用 Intermediate Value Debugger 精确定位问题 kernel 的完整工作流。AOT Inductor 与 CUDA IMA 调试的整体思路AOT Inductor常缩写为 AOTI是 PT2PyTorch 2编译栈的一部分与torch.compile类似但它生成的是一份可以在C 环境中运行的编译产物shared library 导出模型结构而非依赖 Python 运行时。由于其产物直接以裸 kernel 调用的形式执行一旦出现越界写、野指针等内存错误往往表现为 CUDA IMA——而这类错误可能非确定性地出现在不同位置甚至偶尔完全不出现不出现只是意味着数值已静默错误。针对这一特性官方调试指南将排查过程划分为三个高层步骤本文即按此骨架展开Sanity checks健全性检查先用现成的调试开关快速排除常见问题Pinpoint the CUDA IMA锁定错误位置让非确定性错误变得可复现、可定位Identify problematic kernels识别问题 kernel用中间值调试器检查 kernel 的输入与输出。Step 1健全性检查——先用两个编译期开关探路在投入精力做可靠复现之前先尝试已有的调试标志AOTI_RUNTIME_CHECK_INPUTS1 TORCHINDUCTOR_NAN_ASSERTS1这两个开关在编译期更精确地说是代码生成阶段生效AOTI_RUNTIME_CHECK_INPUTS1在运行时检查输入是否满足编译期间使用的同一组 guard形状/步幅守卫。从源码看该开关与 AOTI 配置中的 lowerbound/upperbound 动态形状约束检查协同工作torch/_inductor/config.py中check_lowerbound默认True检查[2, ...]下界约束与check_upperbound默认True根据 lowering 输入与动态形状规格推断上界两项配置共同决定了运行时对动态形状边界的校验强度见 config.py。这一开关主要用于确认输入是否合法从而把动态形状越界类问题提前暴露出来。TORCHINDUCTOR_NAN_ASSERTS1在每个 Inductor kernel 的前后插入 NaN 检查代码用于快速发现数值异常NaN/Inf从哪个 kernel 开始产生。源码中对应nan_asserts os.environ.get(TORCHINDUCTOR_NAN_ASSERTS) 1见 config.py。提示若只想针对 Triton kernel 做运行时 NaN 检查仓库还提供TORCHINDUCTOR_RUNTIME_TRITON_NAN_ASSERTS1的独立开关见 config.py。此外还有一组兄弟开关如TORCHINDUCTOR_SIZE_ASSERTS默认开启生成代码中放置形状断言与TORCHINDUCTOR_SCALAR_ASSERTS默认开启放置符号范围断言可作为健全性检查的补充见 config.py。Step 2锁定 CUDA IMA——让非确定性错误变得可复现CUDA IMA 调试最难的部分在于它的非确定性错误可能发生在不同位置有时干脆不发生尽管数值已经错乱。罪魁祸首通常是 PyTorch 的Caching Allocator它为了减少显存分配次数会一次性分配比实际需求更大的缓冲区并缓存复用这会让越界写恰好落在缓存池内部未使用区域从而掩盖错误。用以下两个运行时开关可以把错误变为确定性触发PYTORCH_NO_CUDA_MEMORY_CACHING1 CUDA_LAUNCH_BLOCKING1Figure: 启用 Caching Allocator 时越界访问落在已分配缓存块内部的空闲区域illegal memory access但不抛错标注no error禁用后同一越界访问将直接触发错误will throw an error。PYTORCH_NO_CUDA_MEMORY_CACHING1禁用 PyTorch Caching Allocator。由于分配行为退化为用多少、分配多少越界访问不再被预分配的大块缓冲区掩盖错误得以稳定暴露——这正是 IMA 非确定性的最常见来源。CUDA_LAUNCH_BLOCKING1强制 kernel逐个同步启动。若不加此开关异步启动的 kernel 会带来著名的CUDA kernel errors might be asynchronously reported at some other API call警告——错误报告位置与实际出错 kernel 完全错位导致无法定位。注意这两个开关在运行时生效AOTI_RUNTIME_CHECK_INPUTS与TORCHINDUCTOR_NAN_ASSERTS则在编译/codegen 期生效因此应在加载并执行编译产物如 AOTI 生成的.so的程序运行环境中设置。Step 3用 Intermediate Value Debugger 识别问题 Kernel拿到确定性复现后下一步是精确定位出错 kernel并检查其输入输出。AOTI 提供了专门的Intermediate Value Debugger中间值调试器。3.1 先打印 kernel 名称序列锁定出错前最后启动的 kernelAOT_INDUCTOR_DEBUG_INTERMEDIATE_VALUE_PRINTER3该开关在编译期生效会在运行时逐个打印被启动的 kernel 名称。配合 Step 2 的两个运行时开关你就能知道错误发生前刚启动的是哪个 kernel。从源码看该开关对应 AOTI 配置中的debug_intermediate_value_printer环境变量见 config.py取值分四级取值行为0关闭调试输出默认1保存中间张量值2打印中间张量值3仅打印 kernel 名称用于锁定可疑 kernel代码生成侧的实现位于torch/_inductor/codegen/debug_utils.pyIntermediateValueDebuggingLevel枚举定义了PRINT_ONLY 2与PRINT_KERNEL_NAMES_ONLY 3两个级别其中级别 3 只输出 kernel 名而不输出张量内容见 debug_utils.py并相应提供codegen_intermediate_tensor_value_save/codegen_intermediate_tensor_value_print等代码生成钩子见 debug_utils.py。3.2 检查可疑 kernel 的输入必须强调错误发生在某个 kernel不代表这个 kernel 本身有问题。很可能是更早的某个 kernel 产生了错误输出只是错误直到后续 kernel 访问这块内存时才暴露。因此下一步是检查可疑 kernel 的输入是否符合预期AOT_INDUCTOR_FILTERED_KERNELS_TO_PRINTtriton_poi_fused_add_ge_logical_and_logical_or_lt_231,_add_position_embeddings_kernel_5 AOT_INDUCTOR_DEBUG_INTERMEDIATE_VALUE_PRINTER2AOT_INDUCTOR_FILTERED_KERNELS_TO_PRINT指定想检查的 kernel 名称列表逗号分隔。源码中该变量会被解析成小写列表逐个与 kernel 名做包含匹配见 debug_utils.py当级别为 2 且当前 kernel 不在过滤列表中时会跳过打印见 debug_utils.py避免海量输出淹没关键信息。AOT_INDUCTOR_DEBUG_INTERMEDIATE_VALUE_PRINTER2开启中间值打印配合过滤列表只输出目标 kernel 的输入/输出张量信息形状、数值等。如果发现该 kernel 的输入不符合预期就继续向上游追溯检查产生该输入的那个 kernel回到 3.1 的 kernel 名称序列找到对应的前驱 kernel用同样的过滤 打印流程复查其输出如此沿数据依赖链逐级回溯直到找到第一个产生错误数值/越界访问的源头 kernel。补充调试工具日志与追踪tlparse / TORCH_TRACE提供完整的输出代码供人工检查并记录编译期使用的 guard 集合。AOTI 的 guard 信息对动态形状类 IMA 尤其重要因为运行时输入若不满足编译期 guard 就可能引发内存错误。TORCH_LOGS使用TORCH_LOGSinductor,output_code查看更详细的 PT2 内部日志其中output_code会输出 Inductor 生成的实际 kernel 代码——配合上文 kernel 名序列可以直接核对每个 kernel 的索引计算与边界条件。TORCH_SHOW_CPP_STACKTRACES设置TORCH_SHOW_CPP_STACKTRACES1可尝试获得更完整的 C 调用栈帮助在崩溃时定位到具体代码路径。常见问题来源动态形状Dynamic shapes历史上一大 IMA 来源。动态形状下符号边界Symbolic bounds推断不准确、guard 未覆盖实际输入范围都容易导致越界。调试动态形状场景时需格外关注 Step 1 的AOTI_RUNTIME_CHECK_INPUTS与 AOTI 配置中的check_lowerbound/check_upperbound行为。深入理解动态形状的语义与约束可参考仓库中的 动态形状指南。自定义算子Custom ops尤其是用 C 实现且配合动态形状使用的自定义算子。此时需要将 meta functionSymintify即把元函数中涉及形状的参数从普通 int 改为 SymInt否则符号形状信息无法正确传递下游 kernel 的边界计算就可能出错。排查流程速查表阶段目标关键环境变量生效时机Step 1 健全性检查快速排除输入/数值异常AOTI_RUNTIME_CHECK_INPUTS1、TORCHINDUCTOR_NAN_ASSERTS1编译期codegenStep 2 锁定错误让 IMA 确定性复现并同步启动PYTORCH_NO_CUDA_MEMORY_CACHING1、CUDA_LAUNCH_BLOCKING1运行时Step 3 定位 kernel打印 kernel 启动序列AOT_INDUCTOR_DEBUG_INTERMEDIATE_VALUE_PRINTER3编译期Step 3 检查中间值审查指定 kernel 的输入输出AOT_INDUCTOR_FILTERED_KERNELS_TO_PRINT...AOT_INDUCTOR_DEBUG_INTERMEDIATE_VALUE_PRINTER2编译期整体工作流可概括为先用编译期开关做健全性检查 → 用运行时开关把非确定错误变确定 → 用级别 3 打印 kernel 序列锁定出错位置 → 用级别 2 过滤列表沿数据依赖链向上回溯直到找到真正产生坏数据的源头 kernel。对于动态形状与 C 自定义算子这两类高发场景还需结合 guard 检查与 SymInt 化改造加以防范。相关实现与配置可直接在 config.py 与 debug_utils.py 中继续深入研读。【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考