🏠 总目录📚 本教程 附录A · 报错反查与速查 ←
📑 本页目录(点开跳转)

附录A · 报错反查与速查

⏱ 14 分钟 | ⭐ 撞墙的时候翻这一页:报错原文 → 它到底在说什么 → 去哪一章


🧭 怎么用这一页

这个板块不是 C++ 教程,它只回答一个问题:往下追 PyTorch 会撞到哪几堵墙。 所以这份速查也按「你撞到了什么」组织,而不是按语法点组织。

⚠️ 三张表的用法不同:报错反查表用来定位问题,判据速查用来做决定,术语对照用来读源码和读别人的报错。


🚨 一、报错反查:它到底在说什么

你看到的 它其实在说 去哪一章
undefined symbol: _ZN3c10... 符号对不上。那串 _ZN3c10 是名字修饰(mangling)之后的 C++ 函数名,c10 是 PyTorch 的核心命名空间。你的扩展要的那个符号,在实际加载的库里不存在 04 · ABI 与二进制兼容 第四节
undefined symbol,但函数名看着明明有 ⚠️ 两边的 _GLIBCXX_USE_CXX11_ABI 不一致。同一个函数在两种 ABI 下修饰出来的名字不一样,编译器认为它们是两个函数 04 第二、四节
cannot open shared object file / 库文件找不到 符号是对的,库本身没被找到。这是加载路径问题,不是编译问题 04 第五节
💀 什么都不报,但数据是错的 最贵的一种:结构体在两边的内存布局不一致,读写错位。它不会崩,只会给你错的数字 04 第六节
Could not run 'aten::gelu' with arguments from the 'SparseCPU' backend 分派表里那一格是空的。算子名是行坐标,backend 是列坐标,这句话的意思是「这一行有,但这一列没实现」 05 · 算子怎么注册进 PyTorch 第一节
装 wheel 时提示平台不兼容 wheel 标签和你的 glibc 版本对不上 —— manylinux 那套标签就是在描述「这个包能装在多老的系统上」 04 第七节
程序莫名其妙比单线程还慢 ⚠️ 可能是 false sharing:两个逻辑上无关的变量落在同一条 cache line 上,两个核在互相打架 03 · cache 与数据布局 第六节
对象出了作用域之后再用就崩 悬垂(dangling)。这是这个板块第 02 章真正存在的理由 02 · 值语义与所有权 第七节

⭐ 一条通用判据:undefined symbol 是链接期的事,Could not run 是运行期查表的事。 前者去查 ABI 和编译选项,后者去查分派表 —— 这两条路完全不通,别串。


🧮 二、判据速查:该怎么选

你在犹豫 判据
值传递还是引用传递 ⚠️ C++ 的 = 默认是复制,和 Python 的「贴名字」完全相反。源码里到处是 const Tensor&,就是为了不复制
std::move 要不要用 记住它不移动任何东西 —— 它只是把对象标记成「可以被搬走」,真正搬不搬由接收方决定
用哪种指针 四种指针 = 四种所有权声明。选哪种等于在回答「谁负责释放」
资源怎么保证释放 RAII:把释放绑在析构上。它是 C++ 版的 with
数据怎么摆(AoS 还是 SoA) 看你每次遍历用到几个字段。只用一两个字段就该拆成 SoA,否则每条 cache line 里大半是白搬的
结构体为什么变胖 对齐填充。字段按大小从大到小排,通常能省下来
要不要真去编译 PyTorch ⭐ 多半不需要。06 · 读源码路线图 第五节给了只用 Python 就能查分派表的办法

🔍 三、不下载源码也能查的三件事

想知道 怎么查
某个算子的真实 schema 用 PyTorch 自带的接口直接读,不必去翻 native_functions.yaml
某个算子在哪些 backend 上有实现 torch._C._dispatch_dump("aten::算子名") —— ⭐ 它把那一行的分派表直接打出来
报错到底来自哪一层 从 Could not run 里抽出算子名和 backend,再去 dump 那一行

⚠️ native_functions.yaml 不在 pip 装的 wheel 里 —— 它是构建期的输入文件。 想看算子定义,用上面这两条命令比找源码快得多。


📖 四、术语对照

词 一句话
名字修饰 / mangling 编译器把 C++ 函数名连同参数类型编码成一个唯一符号,_ZN3c10... 就是它的样子
ABI 二进制层面的约定:名字怎么编码、结构体怎么排布、异常怎么传。⚠️ 和 API 是两件事
API 源码层面的约定:函数长什么样、怎么调用。API 兼容不等于 ABI 兼容
manylinux 一套「能装在多老的 Linux 上」的 wheel 标签标准,本质是在钉死一条 ABI 基线
cache line CPU 一次从内存搬的最小单位。你取一个 int,它搬的是一整条
false sharing 两个无关变量落在同一条 cache line,多核互相使对方的缓存失效
AoS / SoA 结构体数组 / 数组的结构体。同一批数据的两种摆法,遍历模式决定该选哪个
RAII 资源获取即初始化:构造时拿、析构时还,异常路径也保证还
悬垂 / dangling 对象已经没了,还有指针或引用指着它
分派表 / dispatch PyTorch 用「算子名 × DispatchKey」两个坐标查实现的那张表
DispatchKeySet 列坐标的集合:CPU / CUDA / SparseCPU / Autograd… 决定这次调用落到哪一格
TORCH_LIBRARY 声明算子的宏。和注册实现的宏各管一件事
pybind11 只需头文件的绑定库,把 C++ 函数包成 Python 能直接调的模块

🔗 这一页连到哪里

去哪 为什么
00 · 怎么用这份教程 六堵墙分别是什么、这个板块不讲什么、以及那些内容在站内哪里
01 · Python 调 C++ 的那条边界 跨语言调用的两笔开销:转换成本,和那把锁
NumPy 与向量化思维 05 · 内存布局与 stride ⭐ cache 那一章的上游:同一个「按行还是按列走」的问题,在 NumPy 里长什么样
PyTorch 这个框架本身 09 · 自定义算子 Python 侧怎么写自定义算子 —— 05 章讲的是它在 C++ 那一半
打卡记录保存在你的浏览器里,首页能看到总进度