实例¶
五个差距,逐一收敛。其中两个最后根本不是 bug —— 这正是那个排序的意义。
前置:缩小精度差距。
例 1:二分到具体 pass¶
症状。 一个多阶段 kernel 的输出不对,且没有任何报错。
第 1–3 步。 容差与输入精度匹配;「可接受差异」表里没有一条适用;提高校验级别也没报出任何东西。
第 4 步。 pypto.debug.torch_codegen 把 IR 变成可执行的 torch,于是 IR 的含义在主机上运行、完全不涉及设备。CompiledProgram.validate_ir 逐 pass 做这件事,二分是机械的:第一个 IR 不再吻合的 pass 就是引入差异的那个。
然后读那两份 IR。 ir.compile(dump_passes=PassDumpLevel.EXPLICIT) 会写出该 pass 前后的 dump,差异就是含义上的改变。
这证明了什么。 一个语义缺陷 —— 编译器改变了程序算的东西。反之,如果每个 pass 都吻合,那就不是这一例,你要的是例 5。
例 2:那个不是元凶的多跳 cast¶
症状。 A5 上一个带 INT32→FP16 转换的 kernel 与参考不符,而 pass dump 显示该转换被展开成了 INT32→FP32→FP16。这个展开是显而易见的嫌疑人。
第 2 步就排除了它。 这条链与直接转换逐位相同:FP16 在 65504 以上饱和,低于它的每个整数在 FP32 里都是精确的,所以 FP32 那一跳从不舍入,只有最后一跳舍入 —— 与直接 INT32→FP16 完全一样。LegalizeTileCast 展开的是 ISA 一条指令发不出来的转换;展开不等于近似。
要带走的判断方法。 只有当某个中间类型无法精确表示落在目标范围内的源值时,链式转换才会产生差异。请对你自己那条链检查这个性质,而不是把「它被展开了」当作证据。见 LegalizeTileCast。
那该去哪找。 回到第 2 步找别的条目,或者进到第 4 步。
例 3:padding 污染了规约¶
症状。 对全为负的数据,行最大值回来是 0.0。而在能被 tile 整除的形状上这个 kernel 是对的。
定位。 第 2 步,然后读 kernel:一个 pl.load(..., valid_shape=[64, vlen]) 喂给了 row_max。padding 参与了规约,而零胜过每一个负值。
改动。 规约前 pl.fillpad(..., pl.PadValue.min) —— 填你即将施加的那个运算的单位元。row_sum 用 PadValue.zero,min 规约用 max。
确认。 不满 tile 的用例现在对上了。注意满 tile 的用例从来没失败过 —— 这正是它能躲过随手测试的原因,见 规约与 softmax。
例 4:split-K,按设计如此¶
症状。 同一份输入,多次运行的结果在末位上不同。
第 2 步就排除了它。 split-K 用原子加把部分积累加进同一个输出,而跨核的顺序不固定。浮点加法不满足结合律,所以末位可能移动。
这是决策,不是修复。 什么都没坏,所以没有东西要修 —— 只有一个选择:
| 想要 | 就做 |
|---|---|
| 逐位可复现 | 在单核上做 K 分块 —— 分块 matmul |
| 那份并行度 | 保留 split-K,把容差设成能反映它的值 |
确认。 跑两遍。如果差异被容差覆盖、且不随输入规模增长,那就是累加顺序,不是缺陷。
例 5:IR 对,数据错¶
症状。 第 4 步显示 IR 在每一个 pass 都吻合,而设备结果仍然是错的。
这排除了什么。 排除了一切语义问题。再怎么读 pass dump 也找不到,因为 pass 不是问题所在。
第 5 步。 标记可疑张量并比对真实数值:
用 python -m simpler_setup.tools.dump_viewer 查看,从输入开始往前走,直到某个张量第一次与主机参考不符。
致命陷阱:
enable_dump_args=2会 dump 每个任务的全部输入输出。在大负载上这会打满主机侧收集器(约 42 MB/s 的排空速率),并让 AICPU 被 STARS op-execute 超时杀掉。请用等级1加上对目标张量的pl.dump_tag。
五例的共同点¶
| 例 | 在哪一步结案 | 是 bug 吗? |
|---|---|---|
| 1 | 第 4 步 | 是 —— 某个 pass |
| 2 | 第 2 步 | 不是 —— 展开是精确的 |
| 3 | 第 2 步 → kernel | 是 —— 在 kernel 里 |
| 4 | 第 2 步 | 不是 —— 按设计如此 |
| 5 | 第 5 步 | 是 —— 非语义性 |
五例中有三例在第 2 步就结案了,而那只花几分钟,其中两例根本不是 bug。若从第 4 步开始,例 2 和例 4 会各花掉几小时且一无所获 —— 因为那里本来就没有东西可找。
参见¶
- 缩小精度差距 —— 这套流程。
- 性能 —— 对「慢」的同类处理。
- LegalizeTileCast —— cast 链的精确性。