开放接口与生态接入——从单算子到 PyTorch、Triton
系列四 · 第 14 篇
一个检测工具光自己好用还不够,得能走进用户千奇百怪的用法里。昇腾算子有各种被调起来的方式:直接写 Ascend C 单算子、经框架的 AclNN 接口、从 PyTorch 走 TorchNPU、乃至用 Triton 写 kernel。msSanitizer 为这些场景准备了两类对外接口。
第一类叫 sanitizer 接口,本质是给 CANN 软件栈用的一组"替身"。它和 ACL 的接口一一对应——malloc、free、memset、memcpy 这些——唯一多出来的是两个参数:文件名和行号。也就是说,谁用了这组接口分配内存,工具的报错就能精确到"哪一行代码干的"。此外还有两个手动上报的口子,供 PyTorch 这类自带内存池的框架主动告诉工具"这一片 GM 现在归这个算子用了",把张量复用缓存那层"锅"摘干净。
这里有个自然的疑问:编译插桩和 DBI 不是已经能查 Kernel 内的内存问题了吗,为什么还需要用户主动调接口?
因为编译插桩的探针“长”在 NPU Kernel 的指令序列里,它能监视 Kernel 每一次对 GM 的读写,但它看不到 Host 侧那一行 aclrtMalloc 到底写在哪个文件第几行。工具从 runtime 层面只能知道“有一块 GM 泄漏了”,却不知道是哪行代码分配的。
sanitizer 接口比 ACL 接口多出来的 filename 和 lineno 两个参数,恰恰是编译器在编译用户源码时才知道的信息。用户把 acl/acl.h 替换成工具提供的头文件,本质是在告诉编译器:“这行分配调用,请把它的源文件位置也传进去。”于是工具就能把泄漏精确报成 main.cpp:55。
这不是工具“多此一举”,而是 Host 侧信息传递通道缺失时的工程折中:编译插桩管 Kernel 边界之内,接口管 Kernel 边界之外,两者互补。
第二类叫 mstx 接口,可以理解成"给内存打标记"的扩展。用户可以自己注册一片内存池、标出池子里二次分配出来的小区域、甚至声明每块区域的读写权限。在二级指针算子、内存池复用这些场景下,光靠 runtime 上报的信息常常对不准,用户在关键处插几行标记,工具就能精准定位到"这一小块"的问题,还能顺带查出越权读写。
mstx 接口解决的则是另一类信息缺失:PyTorch 的内存池会复用 GM,工具从 runtime 层面只能看到“一大块被分配了”,不知道“这一小块现在归哪个算子用”。用户在关键处插几行标记,工具才能把 Kernel 内部的访问和 Host 侧的归属对应起来。
至于接入方式,工具分了四种典型姿势,从直接到间接:
- 内核调用符:最直接的单算子写法,编译时加个选项就能检;
- AclNN:框架统一入口,还是那个编译选项的事;
- PyTorch:给算子插件编译时加选项,再用工具包起 Python 进程,前提是装好 TorchNPU;
- Triton:一条环境变量
TRITON_ENABLE_SANITIZER=1的事,适合尝鲜。
四种方式的共同逻辑始终没变:只要算子最终是被这套编译工具链编出来的,检测就有缝可入。这也正是这套工具设计的聪明之处——它不挑接入姿势,只盯住那条必经之路(编译)和那个必经之口(kernel launch)。
最后一篇,我们收个尾,把散落各处的典型案例和踩坑经验攒成一份排雷手册,方便你上手后少走弯路。
- 点赞
- 收藏
- 关注作者
评论(0)