Back to Mnn

步骤 2:瓶颈分析与方案选择

skills/arm-cpu-optimize/step2-analyze.md

3.6.02.7 KB
Original Source

步骤 2:瓶颈分析与方案选择

目标:根据基线判断该优化该改哪里,避免盲目写汇编或盲目加 unroll。


2.1 先分类瓶颈

类型常见信号优先方向
memory boundeff GB/s 接近 memcpy roofline减少字节、改善连续访问、减少 metadata
unpack/issue boundeff GB/s 低但指令很多减少 bit unpack、常量复用、调整 layout
compute boundGFLOPS 接近指令峰值更大 tile、更多 accumulator、ISA 指令
postprocess bounddot 快但 scale/minmax/store 慢合并后处理、缩短 min/max live range
dispatch/pack 错配质量错或某 ISA 独坏检查 packer、unit、kernel pointer

w2/w3 常见是 unpack/issue bound,不是单纯 bandwidth bound。


2.2 低 bit kernel 专项分析

分析以下问题:

  • packed cell 的真实字节数是多少?是否有 padding?
  • block32、block64、per-channel 的 metadata stride 是否不同?
  • OC split 时 weightPtr 是否按真实 cell stride 前进?
  • i8mm 和 sdot 是否共享 packer?共享是否安全?
  • sdot/smmla 的 lane 分组和 pack layout 是否完全匹配?
  • fp32 min/max、scale、bias、zp 是否被 unpack 临时寄存器覆盖?
  • E=1 decode 是否走了和 E>1 不同的 kernel?

如果质量问题只出现在一个 ISA,优先查 dispatch/pack/register lifetime。 如果 no-thinking/greedy 正常但 mixed sampling 复读,先不要判定 kernel 错。


2.3 方案优先级

按风险从低到高选择:

  1. 修正确认的 correctness bug:stride、tail、register clobber、dispatch 错配。
  2. 复用已有 CoreFunctions 或已有 kernel 分支。
  3. C++ 层减少拷贝、修正线程拆分、避免 onExecute 分配。
  4. block64/default case 专用分支。
  5. 常量 hoist、ld1r replicate load、减少重复 unpack。
  6. 调整 pack layout,但不增加 packed bytes。
  7. 扩大 unroll 或新增 asm tile。
  8. 增加 packed bytes 或改变量化格式,只有用户明确接受时才做。

2.4 写方案时必须包含

markdown
## 方案

目标路径:
当前瓶颈:
不优化的路径:

Correctness guard:
- C++ oracle:
- op tests:
- model sanity:

实现计划:
1.
2.
3.

性能目标:
- metric:
- expected direction:

风险:
- register lifetime:
- pack/dispatch:
- tail/block:

性能目标可以是方向性的,例如减少 unpack 指令或提升 eff GB/s,不要编造未实测数字。


通过标准

  • 已用数据解释瓶颈,而不是凭直觉。
  • 已明确哪些路径不在本次范围。
  • 已有 correctness guard,能在每个小改动后快速验证。
  • 方案没有依赖用户未接受的格式变化,例如扩大 w2/w3 字节。