多核踩踏——给每一块 GM 内存记上"谁写的"
系列二 · 第 5 篇
昇腾算子里有个特别阴险的 bug:两个核往同一块 GM 地址写数据。谁后写谁说了算,而谁先谁后取决于运行时的调度,于是结果时对时错,复现都复现不出来。业内叫它"多核踩踏"。
它难查的根源在于:单看任何一个核,行为都完全正常,该读读、该写写,挑不出毛病;问题只藏在"两个核的写区间重叠了"这个交集上。传统的加打点、看单核走位,对这种跨核的"撞车"几乎无能为力。
msSanitizer 的解法是回到那张影子账本,给每个字节的记录里多塞一个信息:核归属。还记得吗,第 3 篇说过,每个影子字节拆成"低 2 位状态 + 高 6 位核编号",那高 6 位就是留给"这块地方是谁写的"用的。
逻辑朴素得像在公共白板上写名字:某个核第一次写一个 GM 字节,顺手在账本上记下"这格归我(核 N)“;另一个核也来写同一格,一看账本——“咦,这里已经写了别人的名字”,那就说明两个核写重了,立刻把这一格标成 WARNING ,并报一条"多核踩踏”。
有两点值得琢磨。第一,为什么只有 GM 跟踪核归属?因为 UB、L1、L0 这些片上空间本来就是每个核各用各的,物理上就隔开了,压根不会有"别的核来写我这块"的可能。唯独 GM 是全局共享的,所有核都能碰,才是踩踏的高发地。第二,这份报告为什么是 WARNING 而不是 ERROR?因为"两个核写同一地址"未必就是 bug——比如多个核往结果缓冲区里累加,写地址相同是设计使然。工具只能提示你"这里存在跨核写重叠,请确认是不是故意的",不能武断判错。这正好呼应了第 2 篇说的 ERROR 与 WARNING 之分。
到这儿可以给这三篇做个小结了:影子内存里那"低 2 位 + 高 6 位"的编码,低 2 位管状态,撑起了越界和未初始化检测;高 6 位管归属,撑起了多核踩踏检测。一套账本,两套用途,这是内存检测里我最喜欢的设计。
内存检测(memcheck)的几板斧就齐了。下一篇换个方向,专门讲未初始化——它和越界共用同一套影子账本,但把关的是一句更纯粹的话:这东西,到底被写过没有?
- 点赞
- 收藏
- 关注作者
评论(0)