diff --git a/BMM算子优化分析_Release/MergeBatch_vs_IterBatch分析_v1.0.html b/BMM算子优化分析_Release/MergeBatch_vs_IterBatch分析_v1.0.html new file mode 100644 index 0000000..02350b0 --- /dev/null +++ b/BMM算子优化分析_Release/MergeBatch_vs_IterBatch分析_v1.0.html @@ -0,0 +1,197 @@ + + +
+ + +目标芯片:昇腾 950PR(DAV_3510)。理论分析基于《BMM 算子优化分析 v0.96》,源码参考 [cann-ops-nn](https://gitee.com/ascend/cann-ops-nn) 中 matmul/batch_mat_mul_v3 实现。
+BMM(BatchMatMul)中,当 B ≥ C(batch 数 ≥ AIC 核数)时,核间切 B 是免费的——每核独立处理若干 batch,无共享无依赖。核内的两种实现路径:
+核心问题:什么条件下 MergeBatch 优于 IterBatch?
+核间切 B,每核 $b_{core} = B/C$ 个 batch。核内逐 batch 做标准 Matmul:
+对每 batch i ∈ [0, b_core):
+ GM→L1: 搬入 A_i[M, K] + B_i[K, N](或按 kL1 分块)
+ L1→L0→Cube: 计算 C_i[M, N]
+ Fixpipe: L0C→GM 写回 C_i
+IterBatch 按 L1 容量分四种形态(v0.96 §六):
+| 形态 | 条件 | 特征 |
|---|---|---|
| a) 单 batch 全驻留 | $b_{core}=1$,$(MK+KN) \cdot dtype \le L1$ | 零重复读 |
| b) 双 batch 乒乓 | $b_{core}>1$,$2(MK+KN) \cdot dtype \le L1$ | batch 间流水掩盖 |
| c) 一侧驻留+对侧切 K | $MK \cdot dtype \le L1/2$(驻留侧) | 驻留侧零重复读 |
| d) 两侧都切 K | 兜底 | 两侧都有 K 段级重复读 |
核间切 B(同 IterBatch),核内把 $b_0$ 个 batch 合并计算:
+对每合并组 g ∈ [0, b_core/b0):
+ GM→L1: 搬入 A'[b0·M, K] + B'[K, b0·N](单次 DMA,ndNum=1)
+ L1→L0→Cube: 计算 C'[b0·M, b0·N]
+ Fixpipe: L0C→GM 写回(只取对角块,丢弃交叉项)
+交叉项 $(b_0^2 - b_0) \cdot MN$ 被算出但丢弃——浪费比例 $(b_0-1)/b_0$。进入该分支的 case 必然访存 Bound(条件 5 保证),浪费的算力被搬移时延掩盖。
+同时满足($b_0$ = 最小合并数,取 2):
+Step 1:合并数 b₀(L0C + 算存比双上限)
+**Step 2:L0 级 K 粒度 $k_{L0}$(由 b₀ 和 L0A/L0B 决定)**
+**Step 3:L1 级 $k_{L1}$(先反推再截断)**
+先令 $b_{L1}^* = b_0$,由 L1 容量反推 $k_{L1}^*$:
+然后取 $k_{L1} = \min(k_{L1}^*,\; K,\; 512B/dtype)$——不超过 K(K 截断),也不超过 dValue 推荐值 512B。
+**Step 4:$b_{L1}$ 最大化**
+若 $k_{L1}^* > 512B/dtype$,$k_{L1}$ 被 512B 截断,省出的 L1 空间可容纳更多 batch($b_{L1} > b_0$),提升 batch 间流水深度。
+从 kernel 侧源码可直接观察:
+block_mmad_iterbatch.h CopyInA1):ndNum = curIterBatchL1(多块独立寻址,srcNdMatrixStride = M*K)block_mmad_mergebatch.h CopyInA1):ndNum = 1(合并为单块连续搬移,nValue = b0 × M)每次 GM→L1 DMA 搬移有固定开销 $T_{cmd}$(描述符配置 + 地址生成 + 突发启动),与搬移数据量无关。MergeBatch 把 $b_0$ 次搬移合并为 1 次,$T_{cmd}$ 节省 $b_0$ 倍。
+K 截断情形($k_{L1} = K$,整个 K 装入 L1 一块):
+IterBatch 每 batch 一次 GM→L1 搬移;MergeBatch 每合并 batch 一次(覆盖 $b_0$ 个 batch),搬移次数少 $b_0$ 倍:
+L1 绑定情形($k_{L1} < K$,K 需分块):
+MergeBatch 合并后 tile 更大 → $k_{L1}^m = k_{L1}/b_0$ → $n_K^m = b_0 \cdot n_K$。搬移次数相同($b_{core} \cdot n_K$),每次搬移量也相同——MergeBatch 无搬移优势,只剩 drain 惩罚:
+L1 绑定情形 MergeBatch 恒劣于 IterBatch。
+即 MergeBatch 仅在 K 截断(小 M/N 使 $L1/(2(M+N) \cdot dtype) \ge K$)且 $b_{core}$ 足够大时才优于 IterBatch。
+| 维度 | IterBatch | MergeBatch | 差异 |
|---|---|---|---|
| 稳态搬移吞吐 | 相同 | 相同 | 总搬移量相同 |
| GM→L1 搬移命令数 | $b_{core}$ 次 | $b_{core}/b_0$ 次 | **MergeBatch 少 $b_0$ 倍** ← 核心优势 |
| drain 暴露 | $T_{comp} + T_{write}$ | $b_0(T_{comp} + T_{write})$ | IterBatch 少 $b_0$ 倍 ← 核心劣势 |
| L0C 利用率 | 低 | 高 | 访存 Bound 下不影响时延 |
每次 GM→L1 DMA 搬移的固定开销包括:Nd2Nz 描述符配置(ndNum/nValue/dValue/srcStride 等 7 个字段写入 DMA 寄存器)、地址生成与突发启动、与 L1 buffer 的同步握手(SetFlag<MTE2_MTE1> / WaitFlag<MTE1_MTE2>)。量级估计为数十 ns,精确值需实测标定。
batch_matmul_v3_mergebatch_basicapi_tiling.cpp)IsCapable 条件:
+// 源码:https://gitee.com/ascend/cann-ops-nn
+if (batchC < MIN_BATCH_L0 * aicNum) return false; // B < 128,即 b_core < 4
+if (alignK < 64 || M > N) return false; // K ≥ 64,M ≤ N
+if (L0 buffer check with b0=4) return false; // L0C 容量
+对比分析:
+| 维度 | 理论 | 源码 | 差异 |
|---|---|---|---|
| 合并数 b₀ | min(L0C 上限, 算存比上限, b_core) | MIN_BATCH_L0 = 4(固定),实际由多项式动态求解 | 源码 b₀=4 是硬编码下限,实际值由 L0C 容量动态计算 |
| b_core 下限 | ≥ 2b₀ = 4 | ≥ 4(batchC ≥ 128) | 一致 |
| L0C 约束 | 2(b₀M)(b₀N)·4B ≤ L0C | tempAlignM × tempAlignN × 4B × 2 ≤ L0C | 一致 |
| 搬移量约束 | b_core(MK+KN)·dtype ≥ 480KB | 无 | 源码缺少 |
| tile 大小约束 | max(MK,KN)·dtype ≥ 16KB | 无 | 源码缺少 |
| 算存比约束 | 2MN/(M+N) < R₁₆/b₀ | 无 | 源码缺少 |
| 额外约束 | 无 | K ≥ 64,M ≤ N | 源码独有 |
结论:源码的 MergeBatch 进入条件偏宽——缺少搬移量、tile 大小、算存比三条约束。可能导致不应进入的 case 被误捕获(如计算 Bound 的 case 进入 MergeBatch 后冗余计算成为瓶颈)。
+batch_matmul_v3_iterbatch_basicapi_tiling.cpp)IsCapable 条件:
+// 源码:https://gitee.com/ascend/cann-ops-nn
+if (batchC <= aicNum) return false; // B ≤ 32 不进 IterBatch
+if ((alignM*alignK + alignK*alignN)*dtype*2 > L1) return false; // L1 双缓冲
+if (!l0CanLoadBatch_ && balanceRate < 0.8) return false; // 负载均衡
+对比分析:
+| 维度 | 理论 | 源码 | 差异 |
|---|---|---|---|
| L1 形态 | 四种(a/b/c/d) | 只覆盖形态 b | 源码缺 a/c/d |
| B 下限 | b_core ≥ 1 | B > 32(b_core ≥ 2) | 源码排除了 b_core=1 的形态 a |
| 负载均衡 | B mod C ≥ minCoreNum | balanceRate ≥ 0.8 | 实现方式不同,目的一致 |
结论:源码的 IterBatch 只覆盖形态 b(双 batch 乒乓),且要求 B > C。形态 a/c/d 的 case 由 ASW/AL1/BL1 分支承接。
+理论分析的价值在于:
+源码实现的价值在于:
+matmul/batch_mat_mul_v3 目录