diff --git a/BMM算子优化分析_Release/ASW_Basic分支分析_v1.1.html b/BMM算子优化分析_Release/ASW_Basic分支分析_v1.1.html index 0751a5d..8f51e3b 100644 --- a/BMM算子优化分析_Release/ASW_Basic分支分析_v1.1.html +++ b/BMM算子优化分析_Release/ASW_Basic分支分析_v1.1.html @@ -183,11 +183,25 @@ $$

六、实现方案

Step 0:BaseM / BaseN 的确定(L0 级 tile,先把 L0C 用满)

-

L0C 是 Cube 的累加器,BaseM × BaseN 是每次 Cube 计算的输出 tile。BaseM/N 应尽量把 L0C 用满——L0C 利用率越高,每次 Cube 计算的输出越大,单位计算的启动/排空开销摊得越薄:

+

L0C 是 Cube 的累加器,BaseM × BaseN 是每次 Cube 计算的输出 tile。BaseM/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 容量决定(L1→L0 搬移无 dValue 要求,dValue 约束的是 GM→L1 的 $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}$ 倍(如 256→362),mCnt/nCnt 相应减小,L2 重复读率降低(单 batch 块数减少 → 每行 A 被更少的组读取)。

+

*时延对比*(单 tile 粒度,BF16 输出):

+ + +
方案tile 大小tile 间流水tile 内流水单 tile 时延
双缓冲181×181(32761 元素)✓(tile N 写出 ∥ tile N+1 计算)max($T_{comp}$, $T_{write}$)
UnitFlag 单缓冲256×256(65536 元素)✓(16×16×16 粒度)max($T_{comp}$, $T_{write}$)
+

两种方案的稳态时延相同(都是 max($T_{comp}$, $T_{write}$)),但 UnitFlag 单缓冲的 tile 更大 → 总 tile 数更少 → 循环开销更小。但当前 BMM ASW kernel 未启用 UnitFlagunitFlag = 0,注释 "each l0 only process one block, disable unit flag"),且源码在 baseM=baseN=256 时已自动选 dbL0C=1(256×256×4B×2 > L0C)——即源码已经是单缓冲 + 无 UnitFlag,tile 到顶但无流水交叠。

+

*建议*:对计算 Bound 的 case 启用 UnitFlag(MMAD 与 Fixpipe 流水并行),可将单 tile 时延从 $T_{comp} + T_{write}$ 降至 $\max(T_{comp}, T_{write})$。对访存 Bound 的 case(MTE2 Bound),UnitFlag 收益小([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 对齐} $$
@@ -346,7 +360,9 @@ $$ cubeBoundEdge = \frac{l2BW}{computePower} + l2CacheUsage \cdot \Big(1 - \frac{l2BW}{hbmBW}\Big) \cdot cmr - \frac{1 + l2BW/hbmBW}{kValue} $$

三项含义:① 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 = 0block_mmad_iterbatch.h L315 注释:"each l0 only process one block, disable unit flag")——MMAD 与 Fixpipe 之间是指令级同步(整个 L0C tile 算完才写出)。若启用 UnitFlag,MMAD 每完成一个 16×16×16 块(512B),Fixpipe 立即写出——tile 内部细粒度流水替代 tile 间粗粒度流水,单缓冲即可达到双缓冲的流水效果。对计算 Bound 的 case,UnitFlag 可将单 tile 时延从 $T_{comp} + T_{write}$ 降至 $\max(T_{comp}, T_{write})$。

7.3 SingleCoreM / SingleCoreN 确定(Step 1)

维度理论源码
概念独立于 L0,由 GM→L1 效率 + L2 复用决定无显式概念,per-core tile = baseM × stepM