105 lines
3.2 KiB
Markdown
105 lines
3.2 KiB
Markdown
# 步骤 3:C++ 层优化与 oracle
|
||
|
||
> **目标**:在进入 asm 前,把语义、layout、内存和调度问题先在 C++ 层解决。
|
||
|
||
---
|
||
|
||
## 3.1 CoreFunctions 复用
|
||
|
||
优先替换能安全复用的循环:
|
||
|
||
| 代码模式 | 可考虑函数 |
|
||
|----------|------------|
|
||
| 大规模 GEMM | `MNNPackedMatMul` |
|
||
| E=1 GEMV | `MNNComputeMatMulForE_1` |
|
||
| scale+bias | `MNNScaleAndAddBias` / `MNNScaleAndAddBiasScalar` |
|
||
| softmax/norm/activation | `MNNSoftmax` / `MNNNorm` / `MNNExp` / `MNNSiLu` |
|
||
| pack/unpack | 对应 `gcore` pack helpers |
|
||
|
||
每处替换都要检查:
|
||
|
||
- 数学语义、layout、转置和 tail 是否一致。
|
||
- `dst == src` 是否安全;不确定就读实现或加小测试。
|
||
- 小 shape 下函数调用和 pack 开销是否值得。
|
||
- 保留手写循环时,原因是否清楚。
|
||
|
||
---
|
||
|
||
## 3.2 C++ 标量 oracle
|
||
|
||
复杂 kernel 必须先写标量 oracle。oracle 可以是临时 debug 代码,也可以是测试中的 reference。
|
||
|
||
低 bit oracle 要显式表达:
|
||
|
||
- bit unpack。
|
||
- zero point / scale / bias。
|
||
- block metadata。
|
||
- fp32 min/max。
|
||
- add-dst。
|
||
- tail 和 OC split。
|
||
|
||
建议分层比较:
|
||
|
||
| 输出 | 目的 |
|
||
|------|------|
|
||
| unpack int weight | 查 bit layout |
|
||
| int32 accumulator | 查 dot/smmla 分组 |
|
||
| dequant FP32 | 查 scale/zp |
|
||
| final dst | 查 postprocess |
|
||
|
||
---
|
||
|
||
## 3.3 C++ SIMD/寄存器模拟
|
||
|
||
当目标是 w2/w3、sdot、smmla、SME2 或复杂 pack/tail 时,写 C++ 模拟版再迁移 asm。
|
||
|
||
要求:
|
||
|
||
- 用局部数组或 `std::array` 表达 lane,不依赖编译器自动向量化。
|
||
- helper 名称对应目标指令,例如 `simulateSdot4`、`simulateSmmla`、`unpackW3Block64`。
|
||
- 变量名尽量对应未来 asm 寄存器角色,例如 `vAcc0`、`vInput0`、`vMin`。
|
||
- 每次改变 unroll、pack layout 或 block64 分支,先让模拟版和标量 oracle 对齐。
|
||
|
||
简单 elementwise NEON 不强制模拟;小 reference + asm register plan 通常足够。
|
||
|
||
---
|
||
|
||
## 3.4 内存和线程
|
||
|
||
检查项:
|
||
|
||
- onExecute 中不要反复 `new`、`malloc` 或大 `std::vector` 临时缓存。
|
||
- 需要 scratch 时,在 onResize 中用 Backend 内存池申请。
|
||
- 多线程按独立输出区域划分,避免写冲突和 false sharing。
|
||
- OC split 的 per-thread pointer 要按真实 packed cell stride 计算。
|
||
- 线程数、tile 数、block 数不要在内层重复计算。
|
||
|
||
不要过早做大小核特化;先让 runtime 现有线程策略和目标 kernel 路径正确。
|
||
|
||
---
|
||
|
||
## 3.5 C++ 阶段验证
|
||
|
||
每个小改动后优先跑 focused test:
|
||
|
||
```bash
|
||
cd build
|
||
cmake --build . -j 8
|
||
./run_test.out op/lowMemory/blockConv 0 1 4
|
||
./run_test.out op/lowMemory/HybridConv 0 1 4
|
||
./run_test.out op/lowMemory/blockConv 0 1 4 # 在 SDOT 目标设备/构建配置上复跑
|
||
./run_test.out op/lowMemory/HybridConv 0 1 4 # 在 SDOT 目标设备/构建配置上复跑
|
||
```
|
||
|
||
如果不是低 bit LLM kernel,替换为对应算子的最小 op test。
|
||
|
||
---
|
||
|
||
## 通过标准
|
||
|
||
- 可复用的 CoreFunctions 已复用,或已说明不复用原因。
|
||
- C++ 标量 oracle 可运行,复杂 SIMD 语义已有 C++ 模拟。
|
||
- 没有引入 onExecute 大临时分配。
|
||
- 线程拆分和 pointer offset 已覆盖非 0 线程。
|
||
- focused correctness test 通过后,再进入 asm。
|