Files
matmul-analysis/BMM/BatchMatmul算子特性分析.md

619 lines
42 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Batch Matmul 算子特性分析
> 版本v1.0 | 目标芯片DV100与昇腾 950PR / DAV_3510 同档32 AIC / 64 AIVGM 1.6TB/sL2 128MB / 5.2TB/s
> 本文目标:任意 shape/dtype/layout 的 BMM case都能系统地推导出其在 NPU 上的**最优软件实现方案**(端到端总时延最短),并论证分支体系的完备性与极小性。
> 阅读主线:第 1 章定义问题 → 第 2 章定义"最优" → 第 3 章推导分支划分 → 第 4 章逐分支给出进入条件与实现方案 → 第 5 章决策流程 → 第 6 章完备性审视(漏洞检查)。
---
## 1. 算子功能与接口
### 1.1 算子功能
Batch MatmulBMM完成**带 batch 维的矩阵乘**计算:对 batch 维的每个索引独立执行一次矩阵乘,再加可选偏置:
$$
C[b, m, n] = \sum_{k=0}^{K-1} A[b, m, k] \cdot B[b, k, n] + bias[b, 1, n]
$$
`C = A @ B + bias`。A、B 输入维度典型为 3 维(支持最多 4 级 batch 维 $b = b_0 b_1 b_2 b_3$ 展平),最后两维做矩阵乘。
### 1.2 接口参数
| 参数 | 形状 | 数据类型 | layout | 说明 |
|---|---|---|---|---|
| 左矩阵 A | `[BatchA, M, K]` | dtypeFP16/BF16/FP8/…) | 典型 ND | 可带转置标记isATrans |
| 右矩阵 B | `[BatchB, K, N]` | dtype | 典型 ND | 可带转置标记isBTrans推理场景可为 weightNz |
| 偏置 bias | `[B, 1, N]` | dtype | 固定 ND | 可为空 |
| 输出 C | `[BatchC, M, N]` | dtype可随路量化 | 典型 ND | BatchC = broadcast(BatchA, BatchB) |
**广播语义**batch 维兼容广播——每一级 batch 维上,两侧取值要么相等、要么为 1输出该维取两者的最大值。注意两类广播的形态差异
- **单边全广播**`BatchA = 1``BatchB = 1`(一侧整体只有 1 个 batch
- **交叉广播**:两侧均大于 1 但不同级为 1例如 `BatchA = (6,1)``BatchB = (1,6)`,则 `BatchC = (6,6)` 共 36 个输出 batch。这类 case **不属于**单边广播,后面第 3、6 章会看到它只能落入通用分支。
### 1.3 case 空间:决定实现方式的特征量
一个 BMM case 的实现方式完全由以下特征量决定:
$$
(\; B,\; M,\; N,\; K,\; \text{dtype},\; \text{layout/转置},\; \text{广播形态} \;)
$$
其中 $B$ = BatchC展平后的输出 batch 数)。后续全部分析就是回答:**给定这组特征量,最优实现是什么。**
---
## 2. 性能模型:什么叫"最优"
### 2.1 总时延 = 流水线最慢的一级
NPU 上 BMM 的执行是核内多级硬件流水的并行——Cube 计算MMAD、GM/L2→L1 搬移MTE2、L1→L0 搬移MTE1、L0C 写出Fixpipe多核并行时各流水级时延可被双缓冲double buffer等机制相互掩盖最终
$$
\boxed{\;T_{total} = \max\big(T_{MMAD},\; T_{MTE2},\; T_{MTE1},\; T_{Fixpipe}\;[,\;T_{Reduce}]\big)\;}
$$
**算子优化的关键就是对瓶颈流水级的优化。** 由此直接得出一个重要的设计自由度——**瓶颈交换**
> 当 MTE2搬移是瓶颈、MMAD计算不是瓶颈时可以牺牲一定 MMAD 时延(例如冗余计算)换取 MTE2 性能提升;反之,当 MMAD 是瓶颈时,可以牺牲一定 MTE2 时延(例如重复搬移)换取计算效率提升。只要瓶颈级时延下降,总时延就下降。
后文会看到:**MergeBatch 就是"牺牲算力换搬移效率"的典型ASW_Basic 切 M/N 就是"牺牲搬移(重复读)换并行度"的典型**——它们的存在正当性都来自这个 max 模型。
### 2.2 目标芯片关键规格与经验常数
| 规格项 | 数值 | 对设计的意义 |
|---|---|---|
| AIC / AIV 核数 | 32 / 641:2 | 核间并行度上限 $C = 32$StreamK 归约可用 AIV |
| Cube 算力 FP16/BF16 | ≈486 TFLOPS单核 ≈ 16×16×16 MAC/拍) | 算存比分子 |
| GM 带宽 | 1.6 TB/s读写共享总线 | 访存 Bound 的分母;读+写互相挤占 |
| L2 Cache | 128MB5.2 TB/s读写各独享 | 重复读取的吸收层Cube 输出写 L2 即算完成 |
| L1 / L0A / L0B / L0C | 512KB / 64KB / 64KB / 256KB每 AIC | 核内分块的容量约束L0C 按 FP32 累加计 |
| UB | 512KB每 AIV | 向量通路/归约 |
**GM→L1 搬移效率ND2NZ达到 90%+ 带宽利用率的四条经验约束**DV100 实测,重要性递减):
1. **参与核数**:建议 32 核并行搬移,至少 3/4 核24 核)并发——核数不足时带宽利用率上限被压低;
2. **单核搬移数据总量** ≥ 480KB`min_DatamountPerCore`
3. **单次搬移 tile 大小** ≥ 16KB`min_TileSize`
4. **dValue**(单次搬移的连续内轴字节数,如非转置 A 的 K 向、非转置 B 的 N 向)≥ 128B建议 256B最好 512B。
> 这些常数480KB、16KB、256B/512B以及后文的 $b_{thr}=4$、$k_{thr}$=32B/dtype、$minCoreNum \approx 0.8 \times 32$)都是**该档芯片的实测经验值**;换芯片时本文的所有逻辑结构不变,只需替换常数表。
### 2.3 算存比与 Bound 判定
**约定**:以"元素"为访存单位1 元素 = dtype 字节),算存比单位为 FLOP/元素。
- case 的固有算存比(不计输出写出):
$$
AI = \frac{2MNK}{(MK + KN)} = \frac{2MN}{M + N} \quad [\text{FLOP/元素}]
$$
- 计入输出写出(写 L2/GM的完整算存比
$$
AI_{full} = \frac{2MNK}{MK + KN + MN} \quad [\text{FLOP/元素}]
$$
- 芯片硬件平衡点(该 dtype 位宽下):
$$
R = \frac{\text{Cube 峰值算力}}{\text{GM 带宽} / \text{dtype 字节}} = \frac{486 \times 2}{1.6} \approx 607.5 \quad [\text{FLOP/元素BF16/FP16}]
$$
**判定规则**$AI < R$ 访存 Bound瓶颈在 MTE2优化重心是搬移效率与复用$AI > R$ → 计算 Bound瓶颈在 MMAD优化重心是 Cube 利用率与流水掩盖)。注意一个有用的事实:低位宽 dtypeFP8、MXFP4算力同倍数翻倍而元素字节同倍数减半$R$ 近似不变,因此该平衡点对该芯片各低位宽 dtype 通用。
**大白话**矩阵乘就像搬砖盖楼——Cube 是起重机算力GM 带宽是供货卡车(带宽)。算存比就是"每块砖要盖多少平米"。每块砖盖的平米数低于起重机的额定配比时,楼永远盖不快,问题出在供货而不在起重机——这时候优化要围绕"怎么少堵车、怎么一次多运点",而不是换更大的起重机。
---
## 3. 分支划分的系统推导
本章是全文逻辑主线:**从分块计算的本质出发,不靠经验罗列,推导出五大分支的划分。**
### 3.1 分块计算的本质与四个可切维度
BMM 在 NPU 上实现的本质是把参与计算的数据分块tile由 32 个 AIC 核**并行 + 串行**地完成这些分块的计算,再组合成最终结果:
$$
C[B, M, N] = \sum_{\kappa} A[B, M, K_\kappa] @ B[B, K_\kappa, N]
$$
分块有 4 个维度:**B、M、N、K**。**核间怎么分这 4 个维度,就是分支划分的第一性问题**(核内分块是第二性问题,属于各分支内部的 tiling
### 3.2 四个维度的切分特征:一张决定性的表
从"读入 / 计算 / 写出"三个视角考察每个维度的核间切分特征(这是后续一切推导的基石):
| 切分维度 | 读入特征 | 计算特征 | 写出特征 |
|---|---|---|---|
| **切 B** | 每个数据块只被固定的 1 个核读取,核间**零重复读** | 每个输出块由 1 个核独立完成,**无核间依赖** | 只写最终结果,无中间结果 |
| **切 M / 切 N** | 切 M 则同一右矩阵块被多核**重复读**;切 N 则同一左矩阵块被多核重复读 | 每个输出块由 1 个核独立完成,无核间依赖 | 只写最终结果,无中间结果 |
| **切 K** | 每个数据块只被固定的 1 个核读取,零重复读 | 每个输出块由**多核共同**完成,存在核间依赖 | **有中间结果写出**,需核间 Reduce 归约 |
为什么特征差异这么大?两条硬件层面的根本原因:
- **B 维在数学上独立**BMM 语义就是逐 batch 独立矩阵乘),所以切 B 天然零重复、零依赖;
- **K 维有 L0C 累加机制**:核内切 K 时,$\tilde K$ 轮 mmad 在 256KB 的 L0C 上原地累加(`cmatrixInitVal=false`),中间结果不出核。一旦把 K 切到**核间**,单核的 L0C 装不下"别的核算的 K 段",部分和必须写出到 GM/L2 workspace再由 AIV 归约——**切 K 是唯一同时破坏"累加不出核"和"输出独占"两条性质的切法**。
### 3.3 完备枚举15 种核间切分组合
4 个维度的任意非空子集都可作为一种核间切分方案,共 $2^4 - 1 = 15$ 种:
$$
\{B\},\{M\},\{N\},\{K\},\{B,M\},\{B,K\},\{B,N\},\{M,K\},\{M,N\},\{K,N\},\{B,M,K\},\{B,M,N\},\{B,K,N\},\{M,K,N\},\{B,M,K,N\}
$$
任何实现方案必属于其中一种 ⇒ 这 15 种是**完备的**。按 §3.2 的特征分组:
| 组 | 组合 | 共同特征 | 优化重心 |
|---|---|---|---|
| 纯 B | {B} | 零重复读,读写数据量固定 | 访存 Bound搬移效率高计算 Bound计算效率高 |
| 含 M/N 不含 K | {M},{N},{M,N},{B,M},{B,N},{B,M,N} | 可能有重复读 | 访存 Bound重复读尽量少 + 搬移效率高;计算 Bound计算效率高 |
| 含 K | {K},{B,K},{M,K},{K,N},{B,M,K},{B,K,N},{M,K,N},{B,M,K,N} | 有中间结果写出 + 归约 | 计算效率高,且归约引入的额外 MTE2/Fixpipe 时延不能成为新瓶颈 |
### 3.4 代价不对称性:切分维度的"价格表"
15 种组合的**代价结构只由两个布尔特征决定**——是否含 K、是否含 M/N。三个维度的"核间切分价格"严格排序:
$$
\text{cost}(\text{切}B) = 0 \;<\; \text{cost}(\text{}M/N) \;\ll\; \text{cost}(\text{}K)
$$
- ** B 免费**零重复读零依赖零中间写出
- ** M/N 廉价但有价**共享矩阵被重复读但若共享部分能驻留 128MB L2重复读以 5.2TB/s 命中 L2 而非 1.6TB/s GM——代价大部分被 L2 吸收配合 swizzle执行顺序编排压缩同时活跃的工作集代价进一步压低
- ** K 昂贵**归约流量 $T_{Reduce} \propto grid_K \times$ 输出量且引入核间同步——这是结构性代价L2 吸收不掉
**"价格表"不是经验 BMM 语义 + L0C 累加机制 + L2/GM 带宽结构三条事实的推论。** 整条分支决策树就是一句话**按价格从低到高购买并行度买不够才加价。**
### 3.5 推导主链:从价格表到五大分支
**第 0 层:问题归约(能降维就不在 BMM 本体里解决)。**
- `BatchA = 1` `BatchB = 1`BMM 可通过维度折叠**转化为普通 Matmul**直接复用 Matmul 的成熟优化体系tilingL2 切分全载不必在 BMM 框架内重新发明轮子 **分支一转Matmul**
- 退化 caseK=0 无计算K=1 无累加深度 Cube 完全或几乎无用改走 AIV 向量通路——这属于"计算通路选择"是正交于切分的前置判断 4.0)。
**第 1 层:归约不掉的 caseBatchA = BatchB = B > 1K ≥ 2必须在 BMM 框架内组织 4 维分块。先买免费的 B 维。**
- $B \ge C = 32$ B 就能填满核此时分两种情形
- ** batch $M \times N$ 够大**能开出大 tileL0C 利用率高Cube 喂得饱)→ 每核逐个 batch 做完整 Matmul 就是最优任何额外切分只增代价 **分支二IterBatch**
- ** batch $M \times N$ 太小** 64×64L0C 利用率仅 6.25%Cube 大片闲置)→ 把多个 batch 在核内合并成大 tile 计算$[bM,K]@[K,bN]$取块对角线输出用冗余算力换 Cube 利用率与搬移效率这类 case $AI$ 天然访存 Bound浪费的算力被搬移时延掩盖(§2.1 瓶颈交换)→ **分支三MergeBatch**
**第 2 层:免费的 B 买不满 32 核,加价买廉价的 M/N。**
- $B < 32$ $P = B \times \lceil M/16 \rceil \times \lceil N/16 \rceil \ge 32$M/N 平面的分块补得上并行缺口)→ M/N或混合切共享矩阵的重复读交给 L2 + swizzle 吸收这是"所有不切 K含共享读取切法"的通用框架 **分支四ASW_Basic**
**第 3 层:廉价维度也买不满,才买昂贵的 K。**
- $P < 32$BMN 都小通常 K )→ 唯一剩余的并行维度是 K付归约代价换并行度当且仅当并行收益 > 归约代价(定量条件见 4.4)→ **分支五StreamK**
```
case (B, M, N, K, dtype, layout, 广播形态)
[0] K=0? → AIV 清零K=1? → AIV 逐元素乘 ← 前置通路层(正交于切分)
│ K ≥ 2
[1] BatchA=1 或 BatchB=1? ──是──→ 转Matmul问题归约复用 Matmul 体系)
│ 否BatchA=BatchB=B>1或交叉广播
[2] 并行度账本P = B·⌈M/16⌉·⌈N/16⌉ 与 C=32 比较
├─ B ≥ 32切 B 可满核)─────────────────────────┐
│ M×N 大Cube 饱 → IterBatch │
│ M×N 小Cube 饿,且访存 Bound → MergeBatch │
│ │
├─ B < 32 且 P ≥ 32 → ASW_Basic切 M/N 补并行, │
│ 共享读取由 L2+swizzle 吸收) │
│ │
└─ P < 32B/M/N 用尽仍缺并行K 大)→ StreamK │
(切 K 买并行,付归约代价)◀──────────────────┘
```
### 3.6 完备性与极小性:五大分支不多不少
**完备性**。对归约不掉的 case15 种组合按"(是否含 K是否含 M/N"坍缩:
- 含 K 的 8 种代价结构相同必付归约grid_K × grid_B × grid_M × grid_N 只是参数差异 ⇒ 1 个分支StreamK统一覆盖
- 不含 K 含 M/N 的 6 种:代价结构相同(共享重复读)⇒ 1 个分支ASW_Basic统一覆盖
- 纯 {B} 的 1 种:核内组织只有两种本质不同的方式——**合并多 batch 一起算**MergeBatch或**逐个 batch 算**IterBatch不存在第三种 ⇒ 2 个分支。
$1 + 1 + 2 = 4$,加上第 0 层的归约分支转Matmul= **5**。任何合法 case 必落其一,无空洞。
**极小性**。每个分支都有它"唯一最优"的 shape 区域,去掉任何一个都会有 case 失去最优实现:
| 分支 | 独占最优的代表 caseBF16 | 替代方案为何更差 |
|---|---|---|
| 转Matmul | BatchB=1, B=128, M=N=K=2048 | 免费折叠后 Matmul 体系的 L2 切分/全载直接可用BMM 分支内重做一遍无收益 |
| IterBatch | B=32, M=N=K=4096 | ASW 切 M/N 引入无谓共享读MergeBatch 引入无谓冗余算力 |
| MergeBatch | B=128, M=32, N=128, K=64 | IterBatch 的 L0C 利用率仅 ~1.6%Cube 空转,搬移 tile 碎(<16KB带宽利用率崩 |
| ASW_Basic | B=2, M=N=8192, K=1024 | B 2 核干活StreamK 付无谓归约 |
| StreamK | B=1, M=N=64, K=65536 | 不切 K P=16 < 32近半核闲置时延差数量级 |
五大分支构成**极小完备集**。
### 3.7 大白话总结
> 把 BMM 想成给 32 个工人分一批"矩阵乘订单"
> - **能整单外包的就别自己干**:一侧只有一个 batch问题其实就是一次普通矩阵乘直接交给成熟的 Matmul 产线转Matmul
> - **按订单分(切 B最省心**每人几单互不干扰零重复搬料、零协调。订单多时单大就一单接一单干IterBatch单太小时一人同时干几单、拼成大活干虽然多做了点无用功反正瓶颈在等料不在干活MergeBatch
> - **订单不够分,就按行/列拆单(切 M/N**大家会重复领同一份料但料放在近处仓库L2多跑几趟近仓库很便宜ASW_Basic
> - **行/列也不够拆,只好沿深度 K 拆**几个人合做同一块输出各算一段再汇总——汇总是要额外开会的Reduce所以只在实在分不满、且 K 足够长时才这么干StreamK
---
## 4. 各分支详解:进入条件与实现方案
> 每节按统一结构展开:**做什么(定义)→ 什么时候进(进入条件逐条 + 每条的理由)→ 怎么做(实现方案与参数求解)→ 与源码对照(批判性)**。
### 4.0 前置通路层K 退化 case
在切分决策之前先做计算通路判断
- **K = 0**无任何计算C = bias 0 AIV 写值
- **K = 1**:退化为逐元素乘 `C = A ⊙ B`无累加深度Cube 16×16×16 粒度浪费 15/16 AIV 向量通路GMUBMulGM远优于 Cube 通路
这一层与"切分维度"正交**五大分支管理的都是 Cube 通路上的 caseK 2**。K 极小 K < 16不足一个 fractal时同理应优先考虑向量通路或尾部补齐
### 4.1 转Matmul问题归约分支
**做什么** `BatchA = 1` `BatchB = 1` batch 维折叠进矩阵维度转化为普通 Matmul计算完成后按需恢复 batch
**为什么这么做**单边 batch=1 BMM 与普通 Matmul 在数学上只差一个维度标签Matmul 的优化体系L2 切分AL1/BL1 全载swizzle BMM 各分支在"单样本"情形下更成熟——**站在巨人肩膀上不重复造轮子**。BMM 本体只研究相对 Matmul 有差异化的 case双侧 batch > 1
**折叠规则与代价(关键的不对称性)**
| 情形 | 折叠方式 | 是否免费 |
|---|---|---|
| `BatchB = 1` | 左矩阵 `[B, M, K]` 的 batch 维与 M 维在 ND 布局下**内存相邻**,直接视图为 `[B·M, K]`;输出 `[B·M, N]``[B, M, N]` 的内存布局逐元素一致 | **完全免费**:零输入重排、零输出 split |
| `BatchA = 1` | 需将右矩阵 `[B, K, N]` 折叠为 `[K, B·N]` | **有代价**B 的 batch 维与 N 维在内存中不相邻(中间隔 K折叠等价于一次 `[B,K,N]→[K,B,N]` 的转置重排O(B·K·N) 读写),且输出 `[M, B·N]` 与目标 `[B, M, N]` 之间存在置换,需要随路 scatter |
> 这一不对称性是对"直接折叠"设想的必要修正(详见 6.2)。`BatchB = 1` 无脑走转Matmul`BatchA = 1` 需比较"重排一次 B + Matmul 收益"与"广播友好的 IterBatch/ASW_BasicA 驻留 L2/L1 天然共享,不重排任何数据)"——大 case 重排代价被摊薄走转Matmul小 case 直接走 BMM 分支。源码中的 `MergeBatchAndMAxis()` 只做了 batchB=1 方向的折叠,与"该方向免费"的判断互为印证。
**进入条件**`BatchA = 1 || BatchB = 1`。其中 `BatchB = 1` 恒进;`BatchA = 1` 时按上述代价比较决定(决策规则见第 5 章)。
**BatchA = BatchB = 1**:纯 Matmul是转Matmul 的特例。
### 4.2 MergeBatch多 batch 合并计算)
#### 4.2.1 做什么
核间按 B 分核(每核负责 $b_{core}$ 个 batch核间无同步无通信。核内**将多个 batch 合并计算**
$$
[b, M, K] @ [b, K, N] \;\Rightarrow\; [bM, K] @ [K, bN] = [bM, bN] \;\xrightarrow{\text{BlockTrace}}\; [b, M, N]
$$
其中 **BlockTrace** 指以 $[M, N]$ 的 block 粒度取结果矩阵的块对角线作为各 batch 的有效输出:$C[i, m, n] = R[iM + m,\; iN + n]$。交叉项(第 i 个 batch 的 A 乘第 j≠i 个 batch 的 B被算出但丢弃——这就是"算力浪费",浪费比例 $(b-1)/b$。
**为什么允许浪费**:进入该分支的 case 必然是访存 Bound条件三保证瓶颈在 MTE2 不在 MMAD浪费的算力被搬移时延掩盖§2.1 瓶颈交换)——**用本来闲置的 Cube 算力,换 tile 变大后的搬移效率与 Cube 利用率**。
#### 4.2.2 进入条件(逐条 + 理由)
设计原则四条:① 硬件时延可流水掩盖double buffer 乒乓);② 满足容量约束(每次计算 L1/L0A/L0B/L0C 放得下);③ GM→L1 搬移高效§2.2 四条经验约束);④ 算力有浪费但计算不能成为瓶颈。
形式化后,进入 MergeBatch 需**同时**满足:
**条件 1batch 够分且够合并)**`BatchA = BatchB`(无广播)且
$$
b_{core} = B / aicNum \ge b_{thr}
$$
$b_{thr}$ 是"多 batch 合并搬移能拿到效率收益"的最小合并数——$b$ 太小时合并的搬移收益抵不过实现复杂度,不如 IterBatch 且完全不浪费算力功耗。DV100 实测经验值 $b_{thr} = 4$。
**条件 2合并数 b 的上下界)**:设核内单次 Cube 计算合并 $b$ 个 batch$b \le b_{core}$),要求 $b \ge b_{thr}$ 且 $b$ 由以下约束共同封顶:
- **算存比约束**(计算不能变成瓶颈):合并后单次计算的算存比 $AI(b) = \dfrac{2bMN}{M + N}$,保持访存 Bound 要求
$$
AI(b) < R \;\Longleftrightarrow\; b < b_{AI} = \frac{R \cdot (M + N)}{2MN}
$$
- **L0C 容量约束**输出 $[bM, bN]$ FP32 累加块须放入 256KB L0C考虑乒乓double buffer则两份
$$
2 \cdot (bM)(bN) \cdot 4\text{B} \le 256\text{KB} \;\Rightarrow\; b \le b_{L0C}
$$
- **L0A/L0B 容量约束**$2 \cdot bM \cdot k_{L0} \cdot \text{dtype} \le 64\text{KB}$ $2 \cdot k_{L0} \cdot bN \cdot \text{dtype} \le 64\text{KB}$乒乓两份同时 $k_{L0}$ 不得低于 Cube 分形下限16bit 位宽下典型 min baseK = 16。注意 L0AB 约束耦合 $k_{L0}$需联合求解
> 乒乓取舍:若 $b_{core}$ 小于"不乒乓时 L0C 允许的合并数上限",说明 batch 余量不足,只能不乒乓(牺牲流水掩盖换合并数);否则乒乓。形式上 $b_{max} = \min(b_{AI}, b_{L0C}^{(\text{是否乒乓})}, b_{core})$。
**条件 3访存 Bound 性质)**
$$
\frac{2MN}{M + N} < \frac{R}{b}
$$
case 固有算存比显著低于平衡点低一个合并倍数 $b$ 的量级)——这是"浪费可被掩盖"的定量保证也是条件 2 $b_{AI} > b$ 的另一写法。
**条件 4K 向搬移效率)**L1 级 K 切分 $k_{L1} = K / StepK$StepK 为正整数),要求 $k_{L1} \ge k_{thr}$DV100 下 $k_{thr} = 32\text{B}/\text{dtype}$BF16 即 16 元素)。理由:$k_{L1}$ 决定 ND2NZ 的 dValue过碎则搬移指令效率崩§2.2 第 4 条)。
**条件 5L1 驻留与 tile 效率)**L1 级 batch 驻留数
$$
b_{L1} = \frac{L1_{size}}{(M k_{L1} + k_{L1} N) \cdot \text{dtype}}, \qquad b_{L1} > b
$$
L1 驻留的 batch 组必须大于单次计算的合并数,否则合并无从谈起),且搬移 tile 大小满足效率:左矩阵非转置时 $\max(b_{L1} M k_{L1} \cdot \text{dtype},\; k_{L1} N \cdot \text{dtype}) > min\_TileSize$16KB左矩阵转置时相应调整。
**条件 6单核搬移总量**
$$
b_{core} \cdot (M k_{L1} + k_{L1} N) \cdot \text{dtype} \ge min\_DatamountPerCore = 480\text{KB}
$$
对应 §2.2 第 2 条:单核搬移数据总量不足时带宽利用率上限被压低。
**条件汇总逻辑**:条件 1 定资格batch 够多),条件 2/3 定上限(别算出瓶颈、别撑爆 L0条件 4/5/6 定下限(搬移效率不能崩)。**上限与下限之间必须有交集,交集为空则该 case 与 MergeBatch 无缘。**
#### 4.2.3 核内 b 与 baseK 的取值优化
进入分支后,$b$ 与 baseK 的具体取值有一个重要性质:**在访存 Bound 前提下,$b < b_{AI}$ b 的取值不影响性能baseK 只需满足分形约束16 倍数也不影响算存比**——因为瓶颈是搬移算力余量内怎么切都一样据此
1. 先由条件 2 $b_{max}$实际 $b$ $[b_{thr}, b_{max}]$ 内取**尽量均匀**$b_{core}$ 整除 $b$)——每次计算的 $b$ 均匀一致对功耗更有利
2. 再由 $b$ 反查 L0AB 允许的最大 baseK$baseK_{max} = \min\left(\dfrac{64\text{KB}}{2 \cdot bM \cdot \text{dtype}},\; \dfrac{64\text{KB}}{2 \cdot bN \cdot \text{dtype}},\; \dfrac{C0_{size}}{\text{dtype}}\right)$向下取 16 倍数
#### 4.2.4 数值例子(把条件过一遍)
caseB=128, M=32, K=64, N=128, BF1632
1. **资格**$b_{core} = 128/32 = 4 \ge b_{thr} = 4$ ✓;
2. **算存比**$AI = 2 \times 32 \times 128 / (32 + 128) = 51.2$ FLOP/元素 $< R = 607.5$ 访存 Bound$b_{AI} = 607.5 / 51.2 \approx 11.86$ $b \le 11$ 都不会进入算力 Bound——算存比约束很宽
3. **L0C 约束**乒乓$2(b \cdot 32)(b \cdot 128) \times 4\text{B} \le 256\text{KB} \Rightarrow b^2 \le 8 \Rightarrow b \le 2$不乒乓则 $b \le 4$)——**L0C 才是真正的紧约束**
4. **取 b = 2**= $b_{core}$ 的因子均匀L0B 给出 $k_{L0} \le 64\text{KB} / (2 \times 2 \times 128 \times 2\text{B}) = 64$$K = 64$ 一步到位baseK = 64
5. **搬移效率**$k_{L1} = 64 \ge k_{thr} = 16$ ✓;单核搬移量 $4 \times (32 \times 64 + 64 \times 128) \times 2\text{B} = 80\text{KB}$ —— **不足 480KB**条件 6 不满足
结论 case "单核搬移总量"一项上不达标——这正是 MergeBatch 条件体系的用处**它提前告诉你瓶颈不在算力而在搬移效率** case 应尝试合并更多 K/提高 $b_{core}$ 数据量或由时延模型与 IterBatch/ASW_Basic 比较后定夺
#### 4.2.5 执行流程
```
核间32 核,每核 b_core 个 batch
核内(每核):
for k_l1 in range(0, K, kL1): # L1 级 K 切分
MTE2: A[bL1组, M, k_l1:k_l1+kL1]、B[bL1组, k_l1:k_l1+kL1, N] → L1乒乓
for b_start in range(0, bL1, b): # 按合并数 b 分组
for k_l0 in range(0, kL1, kL0): # L0 级 K 切分
MTE1: A[bM, kL0] → L0AB[kL0, bN] → L0B
Cube: [bM, kL0] @ [kL0, bN] → L0C 累加
Fixpipe: BlockTrace 取 b 个 [M, N] 对角块 → L2/GM
```
#### 4.2.6 与源码对照(批判性)
源码 `batch_matmul_v3_mergebatch_basicapi_tiling.cpp` IsCapable 条件各级 batchA_i == batchB_i`batchC ≥ 4 × aicNum``alignK ≥ 64``M ≤ N` bias NZ拒绝非连续转置等对照分析
- `batchC ≥ 4 × aicNum` 与草稿 $b_{core} \ge b_{thr} = 4$ **一致**每核至少 4 batch)——合理
- `alignK ≥ 64` 比草稿 $k_{thr}$=32B/dtypeBF16 16 元素保守 4 ——**源码更粗**可能误杀 K∈[16,64) 的可获益 case
- `M ≤ N` **实现便利性约束而非原理约束**——M > N 的镜像 case 在原理上同样可合并(交换合并方向),源码直接放弃,属于覆盖缺口;
- 源码**没有显式的算存比/搬移效率判定**(条件 3/4/6把"是否最优"的责任推给了优先级顺序——本文的条件体系正是对此的补全。
### 4.3 IterBatch逐 batch 计算)
#### 4.3.1 做什么
核间按 B 分核(每核 1 个或多个 batch核间无同步无通信核内**逐个 batch 分别执行标准 Matmul 分块**L1→L0A/L0B→Cube→L0C→Fixpipe并输出。无算力浪费、无跨 batch 依赖——是"切 B"最朴素的形态。
#### 4.3.2 进入条件(三大类 + 理由)
满足以下**任一**
**类 1计算 Bound 型)**
$$
AI_{full} = \frac{2MKN}{MK + KN + MN} \ge R \quad \text{且} \quad BatchA = BatchB,\; b_{core} = B / aicNum \in \mathbb{Z}^+
$$
理由:连输出写出都计入仍是计算 Bound则瓶颈恒在 Cube——只要负载均衡$b_{core}$ 整除,各核同量),逐 batch 计算就是满算力实现,无需任何花哨。
**类 2输出驻留 L2 的均衡型)**
$$
\frac{2MN}{M+N} \ge R_{读GM} \;\;\text{且}\;\; 2K \ge R_{写L2} \;\;\text{且}\;\; MN \cdot \text{dtype} \le L2_{size} \;\;\text{且}\;\; BatchA = BatchB,\; b_{core} \in \mathbb{Z}^+
$$
理由:读侧访存不弱($AI \ge R_{读GM}$);单 batch 输出 $MN \cdot \text{dtype} \le 128$MB 可驻留 L2——Cube 输出写 L2 即算完成,写 GM 的流量被省掉;$2K$ 是"每写出一个元素对应的计算量"$2K \ge R_{写L2}$ 保证写 L2 的 5.2TB/s 也不是瓶颈。三个条件合起来 = **读、算、写三条路都不堵**
**类 3访存 Bound 型)**$\dfrac{2MN}{M+N} < R$ 且同时满足
1. $BatchA = BatchB$ $b_{core} = B / aicNum \ge 1$
2. **负载均衡**访存 Bound 时核负载利用率建议 bAvg/bMax > 0.8(计算 Bound 时建议 100%。操作化表述B 整除核数或尾波B mod aicNum活跃的核数 ≥ minCoreNumDV100 取 0.8 × 32 ≈ 26。注意若只写 `B mod aicNum > minCoreNum` 会误杀整除 case余数 0 恰恰是完全均衡),**判据应以均衡比为准、余数规则为其近似**
3. **单核搬移不重复读**(访存 Bound 下重复读就是纯损失),按 L1 容量分五种形态之一:
- (a) $b_{core} = 1$ 且 $(MK + KN) \cdot \text{dtype} \le L1_{size}$:单 batch 左右矩阵同时驻留 L1零重复读
- (b) $b_{core} > 1$ 且 $2(MK + KN) \cdot \text{dtype} \le L1_{size}$L1 放下 2 个 batch 形成乒乓流水;
- (c) 放不下的,$(MK + KN/Step) \cdot \text{dtype} \le L1_{size}$(或 M/Step 对称):一矩阵不切、另一切分,分块大小仍须 > min_TileSize
- (d) $b_{core} > 1$ 时上一条的半容量版本L1 双 batch 乒乓预算减半);
- (e) 左右都切 K$(M \cdot K/Step + K/Step \cdot N) \cdot \text{dtype} \le L1_{size}$
- 以上 (c)(d)(e) 切分后的分块均须满足搬移效率tile ≥ 16KB、dValue ≥ 128B/256B
#### 4.3.3 设计原理(为什么是这些条件)
1. 核间切 B 零共享零依赖,**唯一的系统性风险是负载不均**——所以均衡是第一条件;
2. 输出须满足 L0C 容量:$MN \cdot 4\text{B} \le L0C$(否则核内还要切 M/N那就不是纯 IterBatch 而是 ASW 行为——但注意 IterBatch 核内**允许**对单 batch 做标准 M/N/K tiling此处的准确含义是"核内 tiling 不构成跨 batch 的耦合"
3. 访存 Bound 时**单核数据不得重复读**——L1 装得下才不重复,装不下就按 Step 切分且切分后仍满足搬移效率下限;
4. 与 MergeBatch 的分工IterBatch 不浪费算力,但需要"单 batch 足够大"撑搬移效率与 Cube 利用率MergeBatch 用浪费换效率,专治小 M×N。两者在 $M \times N$ 的中段重叠,由时延模型仲裁(第 5 章)。
#### 4.3.4 执行流程
```
核间32 核分 batch尽量整除尾波核数 ≥ minCoreNum
核内(每核):
for batch in 本核的 b_core 个 batch: # 逐个 batch
for m_tile / n_tile核内标准 tiling:
for k_tile in range(0, K, baseK):
MTE2 预取下一 k_tile → L1双缓冲
MTE1: L1 → L0A/L0B
Cube: mmad → L0C 原地累加 # K 循环不出核
Fixpipe: L0C → L2写 L2 即完成GM 回写可异步)
```
### 4.4 StreamKK 维核间切分)
#### 4.4.1 做什么
当 B、M、N 三个维度切到最碎仍填不满 32 核时,把 K 维切到核间:多核各算一段 K 的部分和,再归约:
$$
C_{(\beta,\mu,\nu)} = \sum_{c \in group} C^{(c)}_{(\beta,\mu,\nu)} \quad \text{(部分和写 workspaceAIV 归约或原子加)}
$$
#### 4.4.2 进入条件(两条缺一不可)
**条件 1并行缺口存在**:不切 K 时的独立输出块数
$$
P = B \times \lceil M / 16 \rceil \times \lceil N / 16 \rceil < C = 32
$$
源码实现取更保守的 $B \cdot mCnt \cdot nCnt \le aicNum/2$并附加 ND-only无交叉广播确定性等级 1原子加顺序不定等工程限制)。注意**严格的 StreamK 不要求核间完全不切 B/M/N**——它是一般框架 `grid_K × grid_B × grid_M × grid_N ≤ C`纯切 K 只是 grid_B=grid_M=grid_N=1 的特例 B/M/N 能提供部分并行度时应该用组合 grid 把归约组 $grid_K$ 压到最小grid_K 小一档K 的门槛降一档平方级)。
**条件 2归约代价可接受**每核计算时延须远大于归约时延安全系数 α = 10
$$
T_{MMAD/core} \ge \alpha \cdot T_{Reduce}
\;\Longleftrightarrow\;
\frac{K}{grid_K} \;\gtrsim\; grid_K \times 1690
$$
$K \gtrsim grid_K^2 \times 1690$grid_K=2 K 6.8Kgrid_K=4 K 27Kgrid_K=8 K 108Kgrid_K=32 K 1.7M仅极端 case)。同时 $K / grid_K \ge 256$单核 K 段过碎则 tiling 效率崩)。**grid_K 越大对 K 的要求越苛刻——StreamK 内部的 grid 搜索自然淘汰归约过重的配置。**
#### 4.4.3 实现要点
- 部分和写出L0C workspaceGM L2归约由 AIV 执行AIC:AIV = 1:22 AIV 伺候 1 AIC 的部分和流
- 原子加AtomicAdd变体省一遍读回但破坏确定性——源码在确定性等级 > 1 时禁用 StreamK工程上必须保留这个开关
- 核间同步与任务编排建议直接复用 Matmul 高阶 API 的 StreamK 模板(避免手写 CrossCore flagId 冲突)。
#### 4.4.4 与不切 K 分支的关系
StreamK 从不"硬切换"进入:当不切 K 的分支候选已足够快(如已 Cube BoundStreamK 候选的归约开销使其自然落败;只有当 B/M/N 并行度不足导致大量核闲置时StreamK 才以数量级优势胜出B=1、M=N=64、K=65536 时,不切 K 仅 16 核可用StreamK 32 核满负荷)。
### 4.5 ASW_Basic通用切分框架
#### 4.5.1 做什么
不切 K允许切 B/M/N 的**任意组合**——它是"不含 K 且含共享读取"的 6 种切分组合({M},{N},{M,N},{B,M},{B,N},{B,M,N})的统一实现框架,也是 B < 32 P 32 时的最优归宿同时兜住 B 32 IterBatch/MergeBatch 条件不满足的剩余 case。**B 可以大可以小可以等于 1ASW_Basic 是实践中最常命中的分支。**
#### 4.5.2 核心机制swizzle + L2 管理
M/N 的固有代价是共享矩阵的重复读ASW_Basic 用两件武器把代价压到最低
1. **ASW 滑窗蛇形 swizzle** M 向按窗口 $W$ 分组$W = \max\{d : d \mid C,\ d \le \lfloor\sqrt{C}\rfloor\}$32 核取 W=4窗口内蛇形遍历 N 数学效果同一时刻 32 个核活跃的工作集被压缩到"W A 行块 + 一条 B 列块带"L2 足迹最小 共享读取基本命中 5.2TB/s L2 而非 1.6TB/s GM窗口取 $\lfloor\sqrt C\rfloor$ 的最大因子是因为窗口越接近正方形A 行块 + B 列块的 L2 足迹越小且因子性保证整窗被核数均分窗口边界不碎
2. **L2 切分**工作集超过 128MB mL2TileNum × nL2TileNum 切分每个 L2 **错位分核**对角线分配避免多核同时抢同一地址的读读冲突并优先选拖尾小的方案
#### 4.5.3 核间切分维度的选择顺序
按共享代价从低到高
1. **切 B**B 核数零共享永远先试
2. **切 M**B 不够右矩阵 [K, N] 被共享 $KN \cdot \text{dtype} \le 128$MB 则驻留 L2 GM 重复读
3. **切 N**对称
4. **混合切**B×MM×N、…):双向共享 swizzle + L2 切分管理
5. **降核**P 远小于 32 K 也不够格走 StreamK 宁可部分核闲置 case 时延绝对值小调度开销反而主导)。
#### 4.5.4 内部特化(不是独立分支)
- **AL1/BL1 全载**当单边无 batch 且该侧矩阵很小 batchA=1 M 256把整个 A 常驻 L1$\tilde M = 1$、A GML1 搬运只发生一次——这是 ASW 内部"M 不切 + L1 驻留深度拉满"的参数极限不是新分支
- **广播友好形态**交叉广播 case(§1.2 ASW 内通过对广播侧做 L1/L2 驻留处理共享关系与切 M/N 同构
---
## 5. 分支仲裁与整体决策流程
### 5.1 为什么需要仲裁层
4 章的进入条件给出的是各分支的"主场"但主场之间有**重叠区**例如 B 32 M×N 中等时MergeBatch IterBatch 都合法B 较大时 IterBatch ASW_Basic B 等效)。重叠区的最优归属没有解析解必须由统一的时延模型仲裁
$$
\text{branch}^* = \arg\min_{cand \in \bigcup \text{各分支候选}} \max\big(T_{MMAD}, T_{MTE2}, T_{MTE1}, T_{Fixpipe}[, T_{Reduce}]\big)
$$
分支体系的价值在于**候选集完备且无冗余**每个等价类只派一个代表框架生成候选时延模型在等价类内部和边界上做精细仲裁两层缺一不可——只有模型没有分支搜索空间是 15 种组合 × 全部 grid 参数的爆炸只有分支没有模型边界 case 被硬阈值误杀
### 5.2 总决策流程
```
输入B, M, N, K, dtype, layout, 广播形态, bias
├─[0] K = 0 → AIV 清零K = 1 → AIV 逐元素乘TO_MUL 通路)
├─[1] BatchB = 1 → 转Matmul免费折叠 [B·M, K],必选)
│ BatchA = 1 → 比较"重排 B + Matmul" vs "广播友好 IterBatch/ASW"
│ 按时延模型选小者
├─[2] BatchA = BatchB = B > 1
│ 生成四类候选并逐一估算 T_total
│ MergeBatch条件 1~6 全过才生成,见 4.2.2
│ IterBatch三大类条件见 4.3.2
│ ASW_Basic按 4.5.3 顺序试切 B/M/N/混合,含 swizzle 与 L2 切分)
│ StreamKP < 32 且 K 满足 4.4.2 条件 2 时生成grid 搜索)
│ → argmin T_total
└─[3] 输出:分支 + tiling 参数baseM/baseN/baseK、b、bL1、kL1…
+ swizzle 方案 + L2 切分方案 + 预估端到端时延
```
---
## 6. 五大分支设计的完备性审视(漏洞检查)
"转Matmul / MergeBatch / IterBatch / StreamK / ASW_Basic 五大分支 cover 全部 BMM case 最优实现"的设计目标逐条拷问
### 6.1 覆盖矩阵:无空洞
| shape 区域 | 主分支 | 兜底 |
|---|---|---|
| K = 0 / K = 1 | 前置通路层AIV | |
| BatchA=1 BatchB=1 | 转Matmul | ASW_Basic广播友好形态 |
| BatchA=BatchB>1B≥32M×N 大 | IterBatch | ASW_Basic 切 B |
| BatchA=BatchB>1B≥32M×N 小,访存 Bound | MergeBatch | IterBatch |
| 上述但 B<32P32 | ASW_Basic | 降核 ASW |
| P<32K | StreamK | 降核 ASW |
| P<32K 也小 | 降核 ASW_Basic | 此时时延绝对值小调度开销主导分支选择不敏感 |
| 交叉广播BatchABatchB 且均>1 | ASW_Basic | — |
### 6.2 审视发现的问题与修正
设计骨架成立,但有五处需要修正或显式声明,否则会被反例拷问:
**问题 1转Matmul 的方向不对称(原设想的最大漏洞)。** "一侧 batch=1 就折叠成 Matmul"在 BatchB=1 方向免费batch 与 M 内存相邻,输出布局一致);但在 BatchA=1 方向,右矩阵 [B,K,N] 折叠成 [K,B·N] 需要一次真实的转置重排,且输出 [M,B·N] 与目标 [B,M,N] 之间存在置换——"只是输出后按 batch split"的设想在 ND 布局下不成立split 实际是 scatter。修正BatchA=1 时按"重排代价 vs Matmul 收益"走模型仲裁,小 case 留在 BMM 分支内A 单侧数据天然可 L2/L1 驻留共享,本身已接近最优)。
**问题 2交叉广播 case 的归属必须显式声明。** BatchA=(6,1)、BatchB=(1,6) 这类 case 既不进转Matmul两侧都>1也不满足 MergeBatch/IterBatch 的 BatchA=BatchB 前提——它们落入 ASW_Basic对广播侧做驻留。不声明就会显得"五分支有洞"。声明后完备性闭合。
**问题 3K 退化不在五分支内,需前置通路层。** K=0无计算、K=1无累加深度走 AIV 向量通路;这是"计算通路选择"维度,与"切分维度"正交,放在五分支之前判断。源码用 K_EQUAL_ZERO / TO_MUL 两个独立策略处理,印证了这一层的必要性——但它们是通路切换而非新切分等价类。
**问题 4IterBatch 草稿条件 3(2) 的字面表述有误杀。** `B mod aicNum > minCoreNum` 会拒绝 B 整除核数的完全均衡 case余数 0。正确表述应以负载均衡比为准访存 Bound 要求 bAvg/bMax > 0.8,计算 Bound 要求 100%;余数规则只是它的近似操作化。
**问题 5经验常数必须可标定且源码硬编码条件偏粗。** $b_{thr}=4$、$k_{thr}$=32B/dtype、480KB、16KB、dValue≥256B 都是 DV100 档芯片的实测经验值,文档中全部显式参数化(换芯片只换常数表)。对照之下源码把 `batchC ≥ 4×aicNum``alignK ≥ 64``M ≤ N` 等直接写死,其中 `alignK ≥ 64` 比草稿阈值保守 4 倍、`M ≤ N` 放弃了镜像 case——**做最优实现时不应继承这些硬编码,而应按第 4 章的条件体系重新判定**。
### 6.3 与源码 10 策略的关系
源码 arch35 的 10 个策略K_EQUAL_ZERO / TO_MUL / STREAM_K / MERGE_BATCH / ITER_BATCH_BROADCAST / ITER_BATCH / AL1_FULL_LOAD / BL1_FULL_LOAD / ASW_BASIC / BASE与本文五分支不是同层概念
| 源码策略 | 本文归属 |
|---|---|
| K_EQUAL_ZERO、TO_MUL | 前置通路层4.0),正交于切分 |
| STREAM_K | StreamK |
| MERGE_BATCH | MergeBatch |
| ITER_BATCH、ITER_BATCH_BROADCAST | IterBatchbroadcast 变体是广播输入下的数据复用特化单边广播在本文更多由转Matmul 吸收) |
| AL1_FULL_LOAD、BL1_FULL_LOAD | ASW_Basic 的 L1 驻留参数极限4.5.4 |
| ASW_BASIC、BASE | ASW_Basic |
**结论**:源码策略集 = 五分支 × 计算通路 × 驻留/广播特化的展开。五分支是"切分等价类"的最小完备骨架,源码的冗余策略可在新实现中收敛,源码遗漏的(条件 3/4/6 的显式判定、M>N 的 MergeBatch 镜像、转Matmul 的 BatchA=1 方向)正是优化的增量空间。
---
## 7. 总结
1. **最优的定义**$T_{total} = \max(T_{MMAD}, T_{MTE2}, T_{MTE1}, T_{Fixpipe}[, T_{Reduce}])$ 最小;瓶颈交换是合法且必要的手段。
2. **分支的推导**4 维可切 → 15 种组合完备 → 切分特征表(切 B 免费 / 切 M/N 廉价被 L2 吸收 / 切 K 昂贵需归约)→ 按价格从低到高购买并行度 → 坍缩为 MergeBatch、IterBatch、ASW_Basic、StreamK 四个等价类加前置的转Matmul 问题归约层,共五大分支,**完备且极小**。
3. **各分支的条件**都不是孤立经验,而是"资格(并行度够不够)→ 上限(容量/算存比封顶)→ 下限(搬移效率托底)"三层逻辑的实例化;所有经验常数可标定、可移植。
4. **边界不靠硬切**:重叠区由端到端时延模型统一仲裁,分支体系负责候选集的完备无冗余。
5. **设计经受了漏洞拷问**修正了转Matmul 的方向不对称与 IterBatch 均衡条件的字面误杀,显式声明了交叉广播与 K 退化的归属;相对源码实现,本文条件体系更细、更真、覆盖更全。
---
*参考文档《BMM分块计算数学公式》《BMM最优软件实现方案设计》《BatchMatMulV3算子分支实现分析》《BMM从分块计算到四大分支的逻辑推导》源码`ops-nn/matmul/batch_mat_mul_v3`arch35芯片资料昇腾 950PR 架构白皮书与 CANN 9.0.0 性能建模文档。*