v1.1: Step0补L0C双缓冲vs UnitFlag单缓冲分析+§7.2补dbL0C/unitFlag源码事实

This commit is contained in:
2026-08-27 03:32:31 +00:00
parent aee5eb01fb
commit 2fd7751c05

View File

@@ -217,13 +217,38 @@ $$
### Step 0BaseM / BaseN 的确定L0 级 tile先把 L0C 用满)
L0C Cube 的累加器BaseM × BaseN 是每次 Cube 计算的输出 tileBaseM/N **尽量把 L0C 用满**——L0C 利用率越高每次 Cube 计算的输出越大单位计算的启动/排空开销摊得越薄
L0C Cube 的累加器BaseM × BaseN 是每次 Cube 计算的输出 tileBaseM/N **尽量把 L0C 用满**——L0C 利用率越高每次 Cube 计算的输出越大单位计算的启动/排空开销摊得越薄
**L0C 双缓冲 vs UnitFlag 单缓冲**
传统做法用 L0C 双缓冲实现 tile 间流水——计算 tile N+1 fixpipe 同时写出 tile N
$$
\text{BaseM} \times \text{BaseN} = \frac{L0C}{2 \times 4\text{B}} = 32768 \text{ 元素}
\text{BaseM} \times \text{BaseN} = \frac{L0C}{2 \times 4\text{B}} = 32768 \text{ 元素双缓冲}
$$
双缓冲两份FP32 4B/元素)。BaseM/BaseN 的长宽比跟随 SingleCoreM/SingleCoreN进而跟随 M/N对齐 16 的倍数baseK L0A/L0B 容量决定L1L0 搬移无 dValue 要求dValue 约束的是 GML1 $k_{L1}$
但昇腾 950PR Fixpipe 支持 **UnitFlag**——MMAD 每完成一个 16×16×16 基本块512B 结果Fixpipe 立即将其写出无需等整个 L0C tile 算完UnitFlag 提供的是 **tile 内部的细粒度流水**16×16×16 粒度替代双缓冲的 **tile 间粗粒度流水**BaseM×BaseN 粒度)。
UnitFlag 单缓冲下L0C 只需一份 buffer
$$
\text{BaseM} \times \text{BaseN} = \frac{L0C}{4\text{B}} = 65536 \text{ 元素单缓冲}
$$
BaseM/N 可放大 $\sqrt{2}$ 256362mCnt/nCnt 相应减小**L2 重复读率降低** batch 块数减少 每行 A 被更少的组读取)。
*时延对比* tile 粒度BF16 输出
| 方案 | tile 大小 | tile 间流水 | tile 内流水 | tile 时延 |
|---|---|---|---|---|
| 双缓冲 | 181×18132761 元素 | ✓(tile N 写出 tile N+1 计算 | | max($T_{comp}$, $T_{write}$) |
| UnitFlag 单缓冲 | 256×25665536 元素 | | ✓(16×16×16 粒度 | max($T_{comp}$, $T_{write}$) |
两种方案的稳态时延相同都是 max($T_{comp}$, $T_{write}$) UnitFlag 单缓冲的 tile 更大 tile 数更少 循环开销更小。**但当前 BMM ASW kernel 未启用 UnitFlag**`unitFlag = 0`注释 "each l0 only process one block, disable unit flag"且源码在 baseM=baseN=256 时已自动选 dbL0C=1256×256×4B×2 > L0C——即**源码已经是单缓冲 + 无 UnitFlag**tile 到顶但无流水交叠。
*建议*:对计算 Bound 的 case 启用 UnitFlagMMAD 与 Fixpipe 流水并行),可将单 tile 时延从 $T_{comp} + T_{write}$ 降至 $\max(T_{comp}, T_{write})$。对访存 Bound 的 caseMTE2 BoundUnitFlag 收益小([CANN 文档](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/920beta1/API/ascendcopapi/atlasascendc_api_07_0003.html)MTE2 Bound 时 MMAD/FIX 流水可被搬移掩盖)。
BaseM/BaseN 的长宽比跟随 SingleCoreM/SingleCoreN进而跟随 M/N对齐 16 的倍数。baseK 由 L0A/L0B 容量决定L1→L0 搬移无 dValue 要求dValue 约束的是 GM→L1 的 $k_{L1}$
$$
baseK = \min\Big(\frac{L0A}{2 \cdot \text{BaseM} \cdot \text{dtype}},\; \frac{L0B}{2 \cdot \text{BaseN} \cdot \text{dtype}}\Big) \text{ 向下 16 对齐}
@@ -465,7 +490,11 @@ $$
三项含义:① L2 供数速率 ÷ Cube 耗数速率理论阈值);② 工作集超 L2 时的访存惩罚抬高 edge倾向更大 tile);③ K 向复用修正K 越大 edge 越小 compute bound)。乘以 CUBE_BOUND_RATIO=0.85 余量枚举 baseM/baseN 递减balanceRate 0.9 剪枝
**差异分析**理论直接 L0C 满载32768 元素源码用 256×256=65536 元素——**源码的 baseM×baseN 是理论上限的 2 **这说明源码的 baseM/baseN 不是 L0C tile 尺寸而是 SingleCoreM/N 级参数源码 L0 tile stepM/stepN 二次切分决定per-core tile = baseM × stepM)。理论的分层SingleCoreM BaseM在源码中无显式概念
**差异分析**理论修正前按双缓冲 L0C 满载的一半32768 元素源码用 256×256=65536 元素——**源码的 baseM×baseN 恰好等于 L0C 单缓冲上限**256×256×4B = 256KB = L0C源码 dbL0C 逻辑`dbL0C = (baseM × baseN × 4B × 2 > L0C) ? 1 : 2`——baseM=baseN=256 512KB > 256KB自动选 dbL0C=1单缓冲
这说明源码的 baseM/baseN 不是 L0 级 tile 尺寸,而是 SingleCoreM/N 级参数。源码中 L0 级 tile 由 stepM/stepN 二次切分决定per-core tile = baseM × stepM。理论的分层SingleCoreM ≥ BaseM在源码中无显式概念。
**UnitFlag 现状**BMM ASW kernel 中 `unitFlag = 0``block_mmad_iterbatch.h` L315 注释:"each l0 only process one block, disable unit flag"——MMAD 与 Fixpipe 之间是**指令级同步**(整个 L0C tile 算完才写出)。若启用 UnitFlagMMAD 每完成一个 16×16×16 块512BFixpipe 立即写出——tile 内部细粒度流水替代 tile 间粗粒度流水,单缓冲即可达到双缓冲的流水效果。对计算 Bound 的 caseUnitFlag 可将单 tile 时延从 $T_{comp} + T_{write}$ 降至 $\max(T_{comp}, T_{write})$。
### 7.3 SingleCoreM / SingleCoreN 确定Step 1