逆向工程高通NPU编译器

Lobsters AI 2026-06-22T09:43:08.017808

逆向工程高通NPU编译器

我的工作是最大限度地利用NPU,使任何我们想要在其上运行的模型在边缘部署时更快。但网络上关于NPU的文档基本不存在,而仅有的一点内容也令人失望,以至于我曾一度想放弃——于是我转而逆向工程编译器。我之前写过一篇关于NPU:是什么,以及它们哪里出了问题的小型入门文章,应该足以理解接下来的内容。

对于任何SoC,高通都没有公布VTCM的存储容量。我该如何判断我的张量是否发生了溢出?或者量化是否真的必要?再加上我的好奇心:想知道他们如何在模型在真实硬件上运行之前就模拟其工作,以及涉及哪些优化算法。

我(借助Claude Code)深入研究了QNPU SDK (v2.46.0.260424)中的 *.so 文件,依赖那些在剥离后存活下来的未混淆名称、使用Ghidra反编译的原始机器码,以及在我的Linux上进行的经验性参数扫描。

一些新发现如下(反正没人有耐心读完整篇文章):

附录中包含更多我无法在正文中容纳的信息。

以上就是要点,本文其余部分将涵盖我发现的三个方面,我认为这些内容从未在互联网上的任何地方公开记录过,并且对任何愿意在高通NPU上进行边缘部署的人都会有所帮助。

内存墙

Hexagon芯片上有一块小型的片上暂存内存,称为VTCM(向量紧密耦合内存)。另一边是主内存DDR,但它速度较慢。ML推理的主要瓶颈在于数据传输的开销。在这种情况下,编译器的全部工作就是决定每个时刻哪些数据应该留在VTCM中,因为任何放不下的数据都必须被挪到DDR,之后再取回来,这既昂贵又低效。

模型中的每个张量都有其生命周期。在执行过程中的任一时刻,都有一组张量是活跃的(可称为工作集)。如果这组张量能放入VTCM,那么一切都会很快。如果不能,编译器就会开始插入溢出操作(将张量推到DDR)和填充操作(将其拉回)。这就是我想要找到的悬崖。

使用相同的模型(Qwen 0.8B),在SM8350上,编译器报告溢出5.46 MB,填充33.9 MB,总DDR流量为37.9 MB;而在SM8650(V75)上,没有任何溢出,DDR读取量为1.15 MB。仅因目标芯片不同,DDR读取流量就差了33倍(这是预期的)。但出于某种奇怪的原因,这些芯片在编译输出中报告了相同的VTCM大小——一个只写着“4”的字段。我不知道这个“4”是什么单位,或者它是否是某种代码。无论如何,行为完全不同。我没有恢复实际容量,这是下一步想做的事情。

编译后的二进制文件带有一个称为spillFillBufferSize的元数据字段,当它为0时,表示

查看原文