为 MNN 框架新增算子。包含 Schema 定义、形状计算、几何计算、后端实现、单元测试的完整 TDD 流程。分 5 步执行,每步有独立测试标准。
日本語の概要は準備中です。原文の説明を表示しています。
MNN Hexagon/HVX/HMX DSP 后端(`source/backend/hexagon`)的优化、重构、构建与回归验证。覆盖设备实测的相位分解、测量纪律、v79/v81 双架构差异、常见瓶颈模式、已否证方向与 cDSP crash 诊断。
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
触发条件:优化/重构 MNN Hexagon DSP 代码路径,分析
DSPOpType性能数据,诊断 cDSP crash,或做 Hexagon 侧内存占用测量。
在这个后端里,正确性、设备稳定性和实测数据的价值远高于凭直觉的微优化。本文所有经验规则都由实测得出,多数是某次错误结论换来的。
info().hvxArch、info().maxThreads、运行时查询的 VTCM 大小),不能由环境变量决定。同一颗芯片必须永远走同一条路径。env 开关只允许作为改动开发期的临时 A/B,上线前必须删除 —— MNN_HEXAGON_Q4_GEMV_I8 和 MNN_HEXAGON_PATHA 就是这类,已按此惯例移除。#if 更适合保管它。source/backend/hexagonsource/backend/hexagon/htp-ops-lib/src/dsp.so,同时重编 host(见测量纪律第 1 条,无条件)。.so 拷进 project/android/build_64。DSPOpType 输出。DSPOpType <OP> 的数字,不要只看 RTF 或总墙钟。:nt store 恰恰证明了该相位是 issue-bound),并且能避免下一个人重跑一遍。按项目脚本预期的目录执行命令。
Executor::RuntimeManager::createRuntimeManager 会把 backend runtime 加到创建时当前的 Executor 上。要在 benchmark 期间保持 DSP 电源,必须在 runtime manager 存在之后、从同一个 Executor 创建 activation guard,并让它在被测区间内一直存活;不要为了供电另建一个 Hexagon Executor。cd project/android/build_64cd project/android/build_64 && ../build_64.sh -DMNN_HEXAGON=ON -DMNN_GPU_TIME_PROFILE=ON && ../updateTest.shupdateTest.sh 对未构建的可选二进制会打印 adb: error: cannot stat,属正常。确认 libMNN.so、ModuleBasic.out 和目标 demo 已推送即可。htp-ops-lib/src/dsp/* 之后重编 DSP:
cd source/backend/hexagon/htp-ops-lib && source ~/.bash_profile && sh sync_remote_build.shREMOTE_SSH=<user@buildhost> HTP_OPS_SDK_ENV=<path/to/setup_sdk_env.source> bash sync_remote_build.sh v81sh sync_remote_build.sh v79。libMNN_htpops.so 是按 arch 不同的,所以一次 v79 构建会覆盖 v81 设备的 stub。跨架构构建时屏蔽 adb(PATH=/usr/bin:/bin bash sync_remote_build.sh v79,脚本会打印 skip adb push),再自己把产物拷到另一台设备。.so 的 md5 只能证明"编过一次",永远不能证明"设备上是哪份源码"。设备状态要用行为验证 —— 见测量纪律。cp source/backend/hexagon/htp-ops-lib/outputs/libMNN_htpops.so project/android/build_64/libMNN_htpops.socp source/backend/hexagon/htp-ops-lib/outputs/libMNN_htpops_skel.so project/android/build_64/libMNN_htpops_skel.so下面每一条都是因为违反过一次、得出了一个自信但错误的结论。
libMNN.so,会静默选中不同的 kernel。曾因此把某个点测成 tg128 57.4(权重路径实际被关闭)而不是 89.2。host 增量构建只要几秒,这个错误却要花掉几小时。[MNN::Hexagon] vectorSize=.. vtcmSize=.. maxThreads=.. hvxArch=.. 确认是哪台设备、哪个 skel 架构;std/mean 超过约 2% 的点都要重测。llm_bench -p N 是纯 prefill、-n N 是纯 decode,但 llm_demo 带 prompt 文件跑的时候会混入尾部的 decode 步,所以那次运行里的单算子时间是两个阶段之和。只有确知是哪个阶段贡献的,才能做算子级归因。编译期开关,默认关闭,关闭时零开销。这些是仪器,动手推测之前先用它们。
| 开关 | 位置 | 报告内容 |
|---|---|---|
HTP_MM_PHASE_PROFILE | ops/matmul_q4fp16.c + execute_command.cc | prefill GEMM 各相位 → profile[200..212]:HMX 计算、等权重反量化、DMA 等待、输出写回、激活 shuffle、setup、worker 侧写回/反量化累计时间 |
HTP_QATTN_PHASE_PROFILE | attention_hmx.cc + execute_command.cc | attention 队列线程相位 → profile[244..250]:DMA 等待、HMX 计算、score 写回,外加 K/V 字节数、激活字节数和 dmstart 次数 |
HTP_WATTN_PHASE_PROFILE | attention_sync_process.cc + execute_command.cc | attention worker 相位 → profile[251..255],按 worker 累加:Q 收集、QK 提交+等待、softmax、SV 提交+等待、O 散出 |
一对文件里的 define 都要改,重编后这些值会作为伪算子出现在 DSPOpType 表里。报告吞吐前记得改回关闭。
怎么读:
adb logcat(在 v79 上就到不了,-b all 也不行)。不要把诊断建立在 FARF 探针上,优先用 profile slot —— 它们通过 profile buffer 回传。info().hvxArch 和 info().maxThreads 在 host 侧可用(HexagonRuntime::info());arch 值源自 DSP(commu.cc 把 __HVX_ARCH__ 写进 info 结构体),因此它报告的是 FastRPC 为这颗芯片加载的那份 skel。查询失败会读到 0 —— 按"更旧/更安全的路径"处理。
n_kv_heads = 8 个任务:在 8 线程设备上正好一波跑完,在 6 线程设备上变成两波,尾波只有 2/6 的占用率 —— 足以把一个 30% 的算法收益全部吃掉。对每个划分都要问一句:这个数是不是偶然等于某个硬件参数? 任务数要远多于线程数;当任务开销不均时(因果掩码使靠后的块贵得多)必须先派发最贵的。
反过来也要注意:本来就能填满整波的划分,再细拆只会增加开销 —— 无条件细拆曾让某算子变慢 3.5%。worker_pool.cc 里的 g_max_num_workers 钉死成更窄设备的线程数。若 N 与 N-1 之间出现悬崖、且 N-1 与 N-2 几乎相同,就是波次量化;若是平滑缩放,才是真正的单线程性能差异。正是这一招把"v79 硬件不同"(错)和"任务数恰好等于 v81 的线程数"(对)区分开。hmx_mgr.cc)。另一些则是历史遗留、值得重测 —— 一条被 __HEXAGON_ARCH__ >= 81 门控的 prefill 路径,曾把五项优化整个从 v79 的构建里编译掉,而 host 侧仍在为它们分配 workspace。想新理论之前先对照这些,每一条都在这里至少测到过一次。
以下全部实现并测量过,别再重新推导一遍。
dmlink 连续链 DMA 解耦:实现正确,收益 0 ms。:nt)存储:无收益(但由此得出上面的 issue-bound 结论)。l2fetch:慢 1.7 ms。np,而 vtcm_seq_alloc 是无边界检查的 bump 分配器,第二份直接越界。任何增加 VTCM 占用的改动,都必须在同一个提交里改 host 侧的 sizing。vtcm_seq_alloc 不做边界检查。加宽任何 staging buffer 之前,手算一遍 VTCM 占用。adb kill-server && adb start-server,确认序列号回来之后,才可以对之前那次失败的运行下任何结论。adb logcat -cadb logcat -drg -i "execute_command_group_profile failed|qurt|sysfatal|fatal|crash|tlb|cdsp.*crash|adsp.*crash|segv|signal 11"adb shell "ls -lt /data/tombstones /data/vendor/tombstones /data/vendor/ramdump /data/vendor/ssrdump 2>/dev/null | head -80"adb shell "find /data/tombstones /data/vendor/tombstones /data/vendor/ramdump /data/vendor/ssrdump -maxdepth 2 -type f 2>/dev/null | tail -40"rg -i "cdsp|adsp|qurt|sysfatal|fatal|crash|tlb|page fault|protection|signal|MNN|htp|fastrpc" <pulled_path>[Hexagon] execute_command_group_profile failed with code -2147482610.so 缺失或过期。Hexagon DSP ProfileCommand groupsCommand dirtyDSPOpType <name> (<id>): <time> msHexagon onCopyBuffer Profile~/Download/hvx.pdf。vmem;不对齐访问用 vmemu。用于验证 Hexagon/DSP 内存占用,或对比 CPU 与 forwardtype=10。
config.json 设 forwardtype=10。adb shell ps | grep <process_name>adb shell "awk '/VmRSS:|VmHWM:/{print}' /proc/<PID>/status"adb shell dmabuf_dump <PID>adb shell dumpsys meminfo <PID>adb shell cat /sys/kernel/debug/dma_buf/bufinfo/sys/kernel/dmabuf/buffers,可能需要 root。VmHWM、TOTAL RSS、TOTAL PSS、dmabuf total 或 PROCESS TOTALVmHWM + dmabuf total 近似"进程可见的 DSP 压力"。cos_sim 可接受。DSPOpType 目标耗时,并与明确的基线对比,且基线是改动前能达到的最好配置。git diff --check 干净。.so 已拷贝/推送到位。まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
为 MNN 框架新增算子。包含 Schema 定义、形状计算、几何计算、后端实现、单元测试的完整 TDD 流程。分 5 步执行,每步有独立测试标准。
日本語の概要は準備中です。原文の説明を表示しています。
MNN 各类正确性/回归 bug 的排查入口,按 bug 类别分册组织,本文件只做症状分流。分册:内存别名与生命周期(arena reuse、`MemChunk`、融合引入的别名竞争)、量化误差与导出侧权重损坏(低 bit 打包、导出分块、PyTorch MPS/CUDA 大张量静默错误)、host 侧并发/线程竞争(共享所有权的引用计数被写坏、析构链崩溃、TSAN A/B 与编译期哨兵)、fp16 表示能力不足(长序列复读、position 塌缩,以及「实时计算→预计算查表」重构的三类陷阱)、GPU shader 越界与 command buffer 故障、后端 kernel 隐式假设违反(causal mask、layout 约定)、持久化缓存误信(weight-mmap sync 自我污染、跨模型缓存复用)、逐 run 不同的非确定性(未初始化内存/堆垃圾依赖、多线程动态分发×异构 kernel)。用户报告 MNN 输出乱码/退化、单测或 golden 对不上、改动后回归、换后端结果不同、开某开关才错、结果每次跑都不一样、或崩在析构链上且只在后台线程异步释放时偶现时使用。
日本語の概要は準備中です。原文の説明を表示しています。
MNN CPU 后端(ARM / x86_64 / RISC-V 三侧)的总入口,只做分流不承载技术内容。下分 `optimize/`(为什么慢、该改哪一层)与 `kernel/`(这条 kernel 怎么写对、怎么被选中)两个分支,`shared/` 放两者共用的构建测试跑分命令、env 开关注册表与 RISC-V 开发板远端验证纪律。做 CPU 侧的工作但还不确定该进哪个分支,或需要三侧结构差异对照(第二张函数表按什么分、二级表怎么构造、`Precision_Low` 语义、ISA A/B 怎么做——「三侧不同构对照表」全树唯一一份,就在本文件)时读这里。
日本語の概要は準備中です。原文の説明を表示しています。
MNN CPU 后端 kernel 开发分支(`skills/cpu/` 下,另一分支是 `cpu/optimize` 性能归因)。覆盖标量 oracle → C++ SIMD → intrinsic → 汇编的四级实现阶梯、pack/kernel ABI 契约(tile、cell stride、后处理参数)、CoreFunctions 派发表注册与二级表安全构造、跨 ISA × 精度的正确性门禁,以及 AArch64 / x86_64 / RISC-V 三份实现参考。为 CPU 后端新写或移植 kernel(NEON / SSE / AVX / RVV intrinsic 或 .S 汇编)、新增一层 ISA、改 pack mode 或 tile 参数、把 kernel 挂进函数表时使用。已定位到 kernel 才进本分支。
日本語の概要は準備中です。原文の説明を表示しています。
MNN CPU 后端性能归因分支(`skills/cpu/` 下,另一分支是 `cpu/kernel` kernel 开发)。按五层(Runtime 线程 / Executor 调度 / Layout 内存 / Dispatch 函数表 / Kernel ISA)定位瓶颈,含 bound 类型判定、op 级实验回路、跨框架 op 对 op 对比、跨层不一致的事后定位,以及 ARM / x86_64 / RISC-V 三侧「我到底跑在哪条 ISA 路径上」的诊断面。CPU 上算子或 LLM prefill/decode 慢、线程数或内存占用异常、出现性能回归、要与外部推理框架逐算子对比时使用。
日本語の概要は準備中です。原文の説明を表示しています。
MNN Metal 后端 op/kernel 开发与优化入口。索引各份 sub-doc:性能问题诊断流程(op 单测 + 对手基准定位真瓶颈,优化任务第一站)、kernel 开发规范与优化知识库(命名/写法/GEMV/GEMM/attention + 手段方法论)、算子融合全链路(导出图→converter→Metal 单 dispatch + 融合方法论)、运行时调度(fence/content-cache/H2D/replay + 调度方法论)、构建测试基线、env 开关注册表。根据当前任务选择性阅读对应 sub-doc。
日本語の概要は準備中です。原文の説明を表示しています。