跳转至

实例

五个差距,逐一收敛。其中两个最后根本不是 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_sumPadValue.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 步。 标记可疑张量并比对真实数值:

pl.dump_tag(t)
cfg = RunConfig(platform="a2a3sim", enable_dump_args=1)

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 会各花掉几小时且一无所获 —— 因为那里本来就没有东西可找。

参见