Files
matmul-analysis/BMM/BMM算子优化分析_Release/BMM算子优化分析_v0.7.md

500 lines
37 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.

# BMM 算子优化分析v0.7
> 目标芯片:昇腾 950PRDAV_3510。所有分支进入条件只含 case 形状参数B、M、N、K、dtype与芯片规格参数。
---
## 一、算子功能与接口说明
完成带 batch 的矩阵乘:`C = A @ B + bias`
* 左矩阵 A`[BatchA, M, K]`dtype典型 ND可带转置
* 右矩阵 B`[BatchB, K, N]`dtype典型 ND可带转置
* 偏置 bias`[B, 1, N]`,固定 ND可为空
* 输出 C`[BatchC, M, N]`BatchC = broadcast(BatchA, BatchB)
---
## 二、符号与芯片参数约定
| 符号 | 含义 | 950PR 取值 |
|---|---|---|
| C | AIC 核数aicNum | 32 |
| L1 | 每核 L1 Buffer | 512KB |
| L0A / L0B | 每核 L0A / L0B | 64KB / 64KB |
| L0C | 每核 L0CFP32 累加4B/元素) | 256KB |
| L2 | L2 Cache 容量 / 带宽 | 128MB / 5.2TB/s |
| W_GM | GM 带宽(读写共享) | 1.6TB/s |
| R₁₆ | 16bit 对应位宽算存比 | ≈607.5 FLOP/元素 |
| dValue | 单数据块内数据连续排布长度 | 推荐 256B/512B不建议 <128B |
| min_TileSize | 确保高带宽利用率的单块搬移数据量最小值 | 16KB |
| min_DatamountPerCore | 确保高带宽利用率的单核搬移数据量最小值 | 480KB |
| minCoreNum | 确保高带宽利用率的并行搬移核数最小值 | 0.8C = 26 |
以上数值基于 950PR 实测分析总结对搬移带宽利用率的影响重要性排序为**核数 > 单核搬移总数据量 > 单分块大小 > dValue**。不同 NPU 芯片数值可能略有差异,换芯片时逻辑结构不变、只换常数表。
---
## 三、最优实现分析
### 3.1 性能模型
BMM 的执行是核内多级硬件流水的并行——Cube 计算MMAD、GM/L2→L1MTE2、L1→L0MTE1、L0C 写出Fixpipe各流水级时延可被双缓冲相互掩盖
$$
T_{total} = \max\big(T_{MMAD},\; T_{MTE2},\; T_{MTE1},\; T_{Fixpipe}\;[,\;T_{Reduce}]\big)
$$
**总时延 = 最慢一级流水**,优化的关键是对瓶颈级的优化。由此得到设计自由度——**瓶颈交换**搬移是瓶颈时可牺牲算力冗余计算换搬移效率计算是瓶颈时可牺牲搬移重复读取换计算效率。MergeBatch 是前者的典型ASW_Basic 切 M/N 是后者的典型。
case 固有算存比与 16bit 位宽平衡点:
$$
AI = \frac{2MN}{M+N},\qquad AI_{full} = \frac{2MNK}{MK+KN+MN}
$$
$$
R_{16} = \frac{\text{Cube 峰值算力}}{\text{GM 带宽} / \text{元素字节数}} = \frac{486\ \text{TFLOPS}}{1.6\ \text{TB/s} \,/\, 2\ \text{B}} \approx 607.5\ \text{FLOP/元素}
$$
其中 486 TFLOPS 是乘加各计一次后的标称算力;分母中的 2B 是 16bit 元素字节数,作用是把 GM 带宽折算成元素速率。
$AI < R_{16}$ 访存 Bound瓶颈在 MTE2反之计算 Bound瓶颈在 MMAD)。
### 3.2 实现本质逻辑
BMM 的实现本质是把数据分块tile由全部 AIC 核并行 + 串行完成这些分块的计算再组合成最终结果
$$
C[B,M,N] = \Big\{\,C[B_u, M_i, N_j] = \sum_k A[B_u, M_i, K_k] \cdot B[B_u, K_k, N_j]\,\Big\}
$$
分块有 4 个维度BMNK。**核间怎么分这 4 个维度就是分支划分的第一性问题**核内分块是第二性问题属于各分支内部 tiling)。
四个维度的核间切分特征后续一切推导的基石
| 切分维度 | 读入特征 | 计算特征 | 写出特征 |
|---|---|---|---|
| B | 核间零重复读每个数据块只被 1 个核读取**核内是否重复读另有条件**—— L1 放不下单 batch 完整的 MN 维输入K 维可切段放入kL1<K batch 计算中切 M 会重复读 B N 会重复读 A | 每个输出块由 1 个核独立完成无核间依赖 | 只写最终结果无中间结果 |
| M / N | M 则同一右矩阵块被多核**重复读** N 则同一左矩阵块被多核重复读 | 每个输出块由 1 个核独立完成无核间依赖 | 只写最终结果无中间结果 |
| K | 每个数据块只被固定的 1 个核读取零重复读 | 每个输出块由**多核共同**完成存在核间依赖 | **有中间结果写出,需核间 Reduce 归约** |
差异的根本原因B 维在数学上独立 batch 独立矩阵乘 B 核间天然零重复零依赖K 维有 L0C 累加机制——核内切 K 时多轮 mmad L0C 原地累加中间结果不出核一旦切到核间部分和必须写出 workspace 再归约——** K 是唯一同时破坏"累加不出核""输出独占"的切法**。
4 维的任意非空子集共 $2^4-1=15$ 种切分组合任何实现方案必属其一完备
| | 组合 | 共同特征 | 优化重心 |
|---|---|---|---|
| B | {B} | 核间零重复读核内重复读取决于 L1 驻留形态无中间写出 | 搬移效率 / 计算效率 |
| M/N 不含 K | {M},{N},{M,N},{B,M},{B,N},{B,M,N} | 核间可能有重复读 | 重复读尽量少L2+swizzle 吸收+ 搬移/计算效率 |
| K | 其余 8 | 有中间结果写出 + 归约 | 计算效率且归约时延不能成为新瓶颈 |
核间切分价格严格排序cost( B) = 0 < cost( M/N) cost( K)。 B 核间免费 M/N 的重复读可被 128MB L25.2TB/s vs GM 1.6TB/s+ swizzle 大部分吸收 K 的归约流量 grid_K×输出量且引入核间同步是结构性代价。**整条分支决策树就是按价格从低到高购买并行度买不够才加价。**
### 3.3 分支推导
1. **问题规约**BatchA=1 BatchB=1 折叠转普通 Matmul转MatmulK=0 / K=1 Cube 无用 AIV 向量通路特殊分支与切分正交的前置判断
2. **先买免费的 B**B C 时切 B 可满核 batch M×N 够大 batch IterBatchM×N 太小 batch 合并成大 tile 冗余算力换搬移效率MergeBatch
3. **B 买不满,加价买 M/N** M/N 或混合切重复读交给 L2 + swizzleASW_Basic
4. **B/M/N 都买不满,才买昂贵的 K**核间切 K + 归约StreamK)。
由此得 6 大分支**转Matmul特殊分支IterBatchMergeBatchASW_BasicStreamK**。重叠区 BC M×N 中等时 MergeBatch IterBatch 都合法由端到端时延模型 $T_{total}$ 仲裁分支体系保证候选集完备无冗余
---
## 四、可转 Matmul 分支
### 进入分支条件
$$
BatchA = 1 \;\lor\; BatchB = 1
$$
解释单边 batch=1 BMM Matmul 只差一个维度标签直接复用 Matmul 的成熟优化体系
### 实现方案
* **BatchB=1**:左矩阵 `[B,M,K]` batch 维与 M 维在 ND 下内存相邻紧排直接视图为 `[B·M,K]`输出布局逐元素一致——零重排 split免费转换
* **BatchA=1**:右矩阵折叠为 `[K, B·N]` 需一次真实转置重排O(B·K·N)且输出存在置换需 scatter——有代价A 较小$MK\cdot\text{dtype} \le L1$时优先 A 常驻 L1留在 BMM 分支内广播友好形态A 较大时按广播扩展后分别预估"BMM 分支""重排+转Matmul"的时延择优
---
## 五、MergeBatch 分支
核间切 B每核 $b_{core}$ batch核间无同步核内把 b batch 合并计算$[b,M,K]@[b,K,N] \Rightarrow [bM,K]@[K,bN]=[bM,bN]$BlockTrace 取块对角线得 $[b,M,N]$。交叉项被算出但丢弃浪费比例 (b1)/b)——进入该分支的 case 必然访存 Bound条件 5 保证浪费的算力被搬移时延掩盖
### 进入分支条件(汇总)
同时满足b0 = 单次合并计算的 batch 数下限b0 2
1. $BatchA = BatchB \;\land\; b_{core} = B/C \ge 2b_0$
2. $2 \cdot (b_0 M)(b_0 N) \cdot 4\text{B} \le L0C$
3. $b_{core} \cdot (MK + KN) \cdot \text{dtype} \ge min\_DatamountPerCore$
4. $\max(MK,\; KN) \cdot \text{dtype} \ge min\_TileSize$
5. $\dfrac{2MN}{M+N} < \dfrac{R_{16}}{b_0}$
### 逐条解释
1. **batch 关系与每核份额**无广播才能逐 batch 对应合并每核至少分到 $2b_0$ batch——$b_0$ 是合并搬移有收益的最小合并数 22 组起步才能构成合并组间乒乓流水 $b_{core} \ge 4$)。
2. **L0C 容量**合并 $b_0$ batch 的输出块 $[b_0M, b_0N]$FP32 累加双缓冲两份必须放得下 L0C连最小合并都放不下合并无从谈起
3. **单核搬移总量**单核搬移数据总量低于 min_DatamountPerCore GM 带宽利用率上不去重要性第 2 位的经验约束)。
4. **搬移 tile 大小** batch 单矩阵的最大连续搬移块须达到 min_TileSize合并是在此之上进一步放大不是替代
5. **访存 Bound**合并把单次计算的算存比放大 $b_0$ 倍后仍须低于 16bit 对应位宽算存比 $R_{16}$保证瓶颈留在搬移侧冗余算力被掩盖而非成为新瓶颈
### 实现方案
**Step 1合并数 bL0C + 算存比双上限)**
$$
b \le \sqrt{\frac{L0C}{2 \cdot MN \cdot 4\text{B}}},\qquad b < \frac{R_{16}(M+N)}{2MN}
$$
$$
b = \min\big(\text{两上限},\; b_{core}\big),\quad b_{L0} = b
$$
b 尽量取 $b_{core}$ 的因子每次合并数均匀负载与功耗更优)。
**Step 2L0 级 K 粒度 $k_{L0}$**
$$
k_{L0} = \min\Big(\frac{L0A}{2\,bM\cdot\text{dtype}},\; \frac{L0B}{2\,bN\cdot\text{dtype}}\Big)\ \text{向下 16 对齐 } k_{L0}\cdot\text{dtype} \ge 128\text{B}
$$
解释L0A/L0B 64KB双缓冲两份装入合并后 $bM$ $bN$ × $k_{L0}$ fractal末项是 dValue 下限
**Step 3L1 级 $k_{L1}$、$b_{L1}$**
$$
k_{L1} \ge \min\big(k_{L0\_max},\; 256\text{B}/\text{dtype}\big),\qquad
2\,b_{L1}(M k_{L1} + k_{L1} N)\cdot\text{dtype} \le L1,\qquad
b_{L1} = \min(b_{L1\_max},\; b_{core}) \;\ge\; b
$$
解释$k_{L1}$ GML1 K 向粒度 dValue 推荐值 256B L1 双缓冲两份每份驻留 $b_{L1}$ batch A/B 各一块$b_{L1} \ge b$ 保证合并不断供
---
## 六、IterBatch 分支
核间切 B每核 $b_{core} \ge 1$ batch核间无同步核内逐个 batch 做标准 Matmul 分块计算无算力浪费无跨 batch 依赖" B"最朴素的形态
### 进入分支条件(汇总)
同时满足
1. $BatchA = BatchB \;\land\; b_{core} = \lceil B/C \rceil \ge 1$
2. $B \bmod C = 0 \;\lor\; B \bmod C \ge minCoreNum$
3. L1 容量约束四选一Step >1 的整数):
* a) $b_{core}=1 \;\land\; (MK+KN)\cdot\text{dtype} \le L1$
* b) $b_{core}>1 \;\land\; 2(MK+KN)\cdot\text{dtype} \le L1$
* c) $\big(MK + 2\cdot\tfrac{KN}{Step}\big)\cdot\text{dtype} \le \dfrac{L1}{\min(b_{core},\,2)} \;\;\lor\;\; \big(KN + 2\cdot\tfrac{MK}{Step}\big)\cdot\text{dtype} \le \dfrac{L1}{\min(b_{core},\,2)}$
* d) $2\cdot\tfrac{K}{Step}(M+N)\cdot\text{dtype} \le L1$
4. c/d 切分后:搬移分块 $\ge min\_TileSize \;\land\; dValue \ge 128\text{B}$
### 逐条解释
1. **batch 关系与每核份额**:无广播;每核至少 1 个 batch。
2. **负载均衡**:切 B 核间零共享零依赖,唯一系统性风险是负载不均。整除时完全均衡;不整除时尾波活跃核数须 ≥ minCoreNum保证尾波仍有足够核并发搬移重要性第 1 位的约束是核数)。
3. **L1 容量——核心要求:单 batch 计算不重复读**
重复读发生在**单 batch 内部**L1 放不下单 batch 完整的 M、N 维输入K 维允许切段放入kL1<K核内切 M 会在 K 循环中重复读 B N 会重复读 AIterBatch 进入与否不由算存比判定——即使 case 是计算 Bound重复读引入的额外搬移也可能把它重新拖回访存 Bound所以进入条件直接由 L1 驻留形态刻画
* **a)** 每核 1 batch左右矩阵同时驻留 L1零重复读
* **b)** 每核多 batchL1 同时放下 2 batchbatch 间直接乒乓
* **c)** 一侧驻留 + 对侧切 K$b_{core} \ge 1$ 统一式驻留侧只搬一次零重复读对侧 K 段在预算内双缓冲故系数 2)。**预算分档由 batch 间流水掩盖决定**$b_{core}=1$ 时无 batch 边界全量 L1 可用$b_{core} \ge 2$ 时预算减半L1/2另一半用于在计算当前 batch 期间预取下一 batch 的驻留侧——定量分析见下文"batch 间流水掩盖"
* **d)** 两侧都切 KA/B K 段成对流水双缓冲故系数 2无驻留侧batch 边界天然无缝是驻留侧放不进 L1/2 时的兜底
4. **搬移效率下限**切分把粒度切小必须守住 min_TileSize dValue否则切分本身把带宽打崩
### batch 间流水掩盖分析c/d 的分工)
先明确流水结构fixpipe unitflag 写出由硬件随路完成每个 16×16×16 fractal 算完即自动搬出**写出侧不需要软件排流水**要掩盖的只有"读入MTE2: GML1)↔ 计算Cube"。
* **(c) $b_{core}=1$**每核只有 1 batch不存在 batch 边界驻留侧全程复用对侧 K 段双缓冲段间无缝
* **(c) $b_{core} \ge 2$——关键问题驻留侧在 batch 边界要整体换入怎么掩盖** 若不减预算全量 L1 给当前 batch batch 边界时下一 batch 的驻留侧 A$MK\cdot\text{dtype}$必须整体换入而当前 batch 尾部只剩几个 K 段的计算——掩盖不了整个驻留侧的换入产生气泡。**修正做法** batch 只占 L1/2驻留侧 + 对侧 K 段双缓冲都在这一半另一半 L1 在计算当前 batch 期间预取下一 batch 的驻留侧上一 batch 做最后一个 K 段时下一 batch 的驻留侧已就绪首个 K 段随即搬入——边界无气泡无气泡的定量条件驻留侧换入量 $MK\cdot\text{dtype} \le$ 当前 batch 总搬入量 $(MK+KN)\cdot\text{dtype}$恒成立访存 Bound 下计算时间 搬入时间尾部窗口必然足够
* **(d)两侧都切 K**K 段槽位在 batch 间完全同质连续——上一 batch 最后一段计算时搬下一 batch 第一段天然无缝当驻留侧单矩阵放不进 L1/2 (c) 不成立 (d) 接管代价是两侧都有 K 段级重复读
结论(c) 统一了原 (c)/(d)——同一族"一侧驻留 + 对侧切 K"预算按 $b_{core}$ 分档$b_{core}=1$ 全量 L1、$b_{core} \ge 2$ 减半以容纳下一 batch 驻留侧预取驻留侧超 L1/2 时由 (d) 接管
### 实现方案
**(a)**每核 1 batch 直接搬入 L1L1L0 先看 L0C 能否放下完整单 batch 输出
```
if (L0C >= M*N*4B): # L0C 放得下完整输出:不切 M/N只切 K
BaseM = M; BaseN = N
BaseK = min(align(L0A/M, 16), align(L0B/N, 16))
else: # L0C 放不下:按较小维切
if M < N: BaseM = align(M,16); BaseN = floor(L0C/4B / BaseM)
else: BaseN = align(N,16); BaseM = floor(L0C/4B / BaseN)
BaseK = min(floor_align(L0A/BaseM,16), floor_align(L0B/BaseN,16))
```
**(b)**L1 batch 乒乓核内 GML1L0CubeL0CGM/L2 流水L1L0 分块同理但各级预算减半L0C/L0A/L0B 2 )。
**(c)**一侧驻留 + 对侧切 K假设驻留左矩阵右矩阵搬入的 K 向长度
$$
k_{L1\_b} = \min\Big(\frac{L1_{budget} - MK\cdot\text{dtype}}{N\cdot\text{dtype}},\; K\Big),\qquad L1_{budget} = \frac{L1}{\min(b_{core},\,2)}
$$
$b_{core} \ge 2$ 时另一半 L1 在计算期间预取下一 batch 的驻留侧实现 batch 间无气泡衔接fixpipe unitflag
**(d)**两侧都切 K $k_{L1}$ 取满足容量与 dValue 的最大值L0C batch 乒乓各占 L0C/2batch 边界由硬件 fixpipe 自动排空下一 batch 立即在另一半 L0C 累加
---
## 七、StreamK 分支
### 进入分支条件(汇总)
1. $P = \dfrac{B \cdot MN \cdot 4\text{B}}{L0C} < \dfrac{C}{2}$
2. $\dfrac{K}{grid_K} \ge \dfrac{256\text{B}}{\text{dtype}}$
3. $K \ge grid_K^{\,2} \cdot \theta$其中 $\theta \approx 1.1\times10^{2}$部分和驻留 L2AIV 归约的方案部分和落 GM $\theta \approx 1.7\times10^{3}$
4. 工程约束确定性等级 1核间归约顺序不定ND 格式
### 逐条解释
1. **并行缺口**P "L0C 满载的输出基本块"为粒度估计不切 K 的最大并行度——基本块按 L0C 最大利用率取$M^t N^t \cdot 4\text{B} = L0C$免去预先估计 M/N 具体切分。**阈值取 C/2 而非 C**StreamK 的定义就是 grid_K 2至少 2 路切 K且同一 batch 内所有输出块共享同一个 grid_Kgrid_K=2 时每块需要 2 个核总核数需求 = P × 2 C P C/2 C/2 P < C 2 路就超核数2P > C不切又浪费一半核——这个区间由降核 ASW_Basic 承接更合适。P < C/2 才意味着不切 K 时连一半核都填不满K 是唯一剩余的并行维度
2. **单核 K 段下限**每核 K 段内轴连续长度不小于 dValue 推荐值 256BBF16 128 元素保证段内搬移效率不崩
3. **归约代价可接受**先按实现流程看清 $T_{Reduce}$ 的构成StreamK 每个输出块的执行分三步
**第 1 步AIC 算部分和)**grid_K AIC 各算 K/grid_K 段内多轮 mmad L0C 原地累加不出核——这步的时延就是每核计算时延 $T_{MMAD}$
**第 2 步AIC 写部分和)**每核算完fixpipe 把本核的 $MN \cdot 4\text{B}$ 部分和写到 workspace。**部分和驻留 L2** L2 写口 5.2TB/s不占 GM 总线
**第 3 步AIV 归约)**AIVAIC:AIV=1:2 2 AIV 伺候 1 AIC 的部分和流 grid_K 份部分和从 L2 读回 UBL2 读口 5.2TB/s向量求和结果经 UB 写回 L2/GMAIV 是独立硬件数据流 GM/L2UBAIVUBL2/GM AIC 的计算流水并行
因此每输出块的归约时延为四段之和
$$
T_{Reduce} = \underbrace{\frac{grid_K \cdot MN \cdot 4\text{B}}{W_{L2}}}_{\text{写部分和}} + \underbrace{\frac{grid_K \cdot MN \cdot 4\text{B}}{W_{L2}}}_{\text{AIV 读回}} + \underbrace{\frac{grid_K \cdot MN}{Q_{AIV}}}_{\text{AIV 求和}} + \underbrace{\frac{MN \cdot outB}{W_{L2}}}_{\text{写回}}
$$
而每核计算时延 $T_{MMAD} = \dfrac{2MNK}{grid_K \cdot Q_{16}}$。要求 $T_{MMAD} \ge \alpha \cdot T_{Reduce}$——安全系数 α=10 的含义归约是切 K 新增的流水级其占比压到 ~10% 以内才不改变瓶颈归属代入 $W_{L2}$=5.2TB/s、$Q_{AIV}$ 13.5×10¹² /s64 AIV × 128 fp32/ × 1.65GHz)、$Q_{16}$=13.5 TFLOPSoutB=2B
$$
K \ge grid_K^2 \cdot \frac{\alpha \cdot Q_{16}}{2}\Big(\frac{8\text{B}}{W_{L2}} + \frac{1}{Q_{AIV}}\Big) + \frac{\alpha \cdot Q_{16} \cdot outB}{2 W_{L2}} \approx grid_K^2 \times 109
$$
$\theta \approx 1.1\times10^{2}$grid_K=2 K0.5K4 K1.8K8 K7.0K32 K112K。** K 的要求随 grid_K 平方增长——归约流量与每核收益都随 grid_K 线性涨相抵后门槛剩平方项grid 搜索自然淘汰归约过重的配置。**
注意 $\theta$ workspace 落点敏感若工作集过大部分和无法驻留 L2 而落 GM归约读写降到 GM 有效带宽 0.4×1.6TB/s$\theta$ 升至约 $1.7\times10^{3}$——仍可控 grid_K 的上限被显著压低设计时应优先保证 workspace 驻留 L2
4. **工程约束**归约顺序不定引入浮点非确定性确定性等级 2/3 的业务禁用
**源码对照**`batch_matmul_v3_basic_streamk_tiling.cpp` K 的固定门槛为 `CeilAlign(K,256) ≥ max(8192, aicNum×256B/dtype)`其含义`aicNum×256B/dtype`2048bit/= 全部 AIC 参与切 K 时每核至少分到 256B K 向内轴数据——正是条件 2 dValue 推荐值`8192` = C×256 元素是绝对下限保证每核至少 256 K 元素BF16 512B摊薄切 K 的固定开销workspace 建立归约同步)。两个数字分别对应本文的条件 2 和条件 38192 本模型 grid_K 8 的门槛8²×1097.0K互为印证源码用固定门槛是条件 2/3 的保守近似本文的 grid_K 平方式给出随切份数变化的解析门槛更细
### 实现方案
**核间组织**先按 B/M/N 切出输出块剩余核预算折成 K 向份数
$$
blocksPerBatch = \Big\lfloor \frac{C}{B} \Big\rfloor,\qquad
grid_K = \frac{blocksPerBatch}{mCnt \cdot nCnt}
$$
mCntnCnt 收拢为 blocksPerBatch 的因子避免碎核尾块由条件 1 $mCnt \cdot nCnt \le blocksPerBatch/2$ $grid_K \ge 2$。归约组内核 c 负责 K $[cK/grid_K,\; (c{+}1)K/grid_K)$。
**核内流水**对自己的 K 段做标准分块流水MTE2L1L0mmad段内多轮在 L0C 原地累加段完部分和经 Fixpipe 写出
**归约**
* **workspace + AIV 归约确定性**部分和写 workspace每核 256×256×4B另加 20MB 核间通信区**workspace 优先驻留 L2**——归约读写走 5.2TB/s L2 口而非 GMAIV L2 读回各段部分和 UB 内求和后写回数据流 GM/L2UBAIVUBL2/GMAIC:AIV=1:2
* **AtomicAdd非确定性**:部分和直接原子累加到输出 GM省一遍读回确定性等级 >1 禁用。
**参数搜索**$grid_K$ 从 2 起按 2 的幂递增,取同时满足条件 2/3 的最小值;都不满足则退为降核 ASW_Basic。
---
## 八、ASW_Basic 分支
### 进入分支条件(汇总)
1. $P = \dfrac{B \cdot MN \cdot 4\text{B}}{L0C} \ge C$
2. 无 batch 结构限制BatchA=BatchB、交叉广播均可典型进入路径$B < C$ B 买不满核 $B \ge C$ IterBatch/MergeBatch 条件不满足时的兜底
3. **降核模式**$P < C$ 且不满足 StreamK 进入条件 只用 $\lceil P \rceil$ 个核其余核闲置
### 逐条解释
1. **并行度补齐** L0C 满载为基本块粒度B×M×N 能切出至少 C 个独立输出块则切 M/N或混合切并行度够用 M/N 的固有代价是共享矩阵被多核重复读但共享部分驻留 128MB L2 时重复读以 5.2TB/s 命中 L2 而非 1.6TB/s GM代价大部分被吸收
2. **兜底性质**ASW_Basic 是实践中最常命中的分支——B 可大可小可等 1交叉广播也由此承接对广播侧做 L1/L2 驻留共享关系与切 M/N 同构)。
3. **降核模式**P < C K 也不够格走 StreamK 并行度凑不满核此时与其强行把 M/N 切得更碎tile 跌破 min_TileSizedValue 跌破 128B搬移效率崩塌反而更慢不如**只用 P 个核**、每核承担一个完整输出块L0C 满载粒度其余核闲置这类 case 的时延绝对值小继续切分引入的调度与搬移效率损失大于并行收益——降核是理性选择而非偷懒
### 实现方案
**1、核间切分维度选择按共享代价从低到高** B零共享先试)→ M右矩阵 $KN\cdot\text{dtype} \le L2$ 则驻留 L2)→ N对称)→ 混合切 swizzle + L2 切分管理)→ 降核见第 6 )。
**2、swizzleASW 滑窗蛇形**
**问题**核间切 M/N 同一时刻 C 个核各算一个输出块它们所需的 A 行块与 B 列块集合就是当前"活跃工作集"。若按行优先顺序朴素分配一波 C 个块横跨的 A B 列很宽活跃工作集超过 L2 就回 GM 1.6TB/s重复读代价真实发生。**swizzle 要做的就是编排输出块的执行顺序把每一波核的活跃工作集压到最小。**
**做法** M 向每 W 个基本块划为一个"窗口"遍历顺序为"窗口内先扫 M扫满 W 行再进下一列 N一个窗口扫完再进下一个窗口"且奇数窗口行 N 向反向蛇形)。效果有二
* 同一波 C 个核的块集中在同一个窗口内 活跃 A 行块只有 W 活跃 B 列块只有 C/W 条带
* 蛇形反向使相邻窗口行首尾相接——上一窗口末尾的 B 列带与下一窗口开头的 B 列带是同一条跨窗口切换时工作集增量最小
**W 怎么取**一波 C 个块的 L2 足迹约为
$$
footprint \approx \big(W \cdot M^t K + \tfrac{C}{W} \cdot K N^t\big) \cdot \text{dtype}
$$
由均值不等式$W + C/W$ $W = \sqrt{C}$ 处取最小——窗口越接近"方形"W × C/W 足迹越小同时 W 须整除 C保证每个窗口恰好被整数波核覆盖窗口边界不把波次切碎合起来即
$$
W = \max\{\,d \mid d \mid C,\; d \le \lfloor\sqrt{C}\rfloor\,\}
$$
C=32 $\sqrt{32} \approx 5.66$因子 {1,2,4,8,…} 中不超过它的最大者是 4 W=4。
**实例**C=32W=4M̃=8Ñ=8数字为块的全局执行顺序一波 32
```
窗口0N 正向) 窗口1N 蛇形反向)
ν0 ν1 ν2 … ν7 ν0 ν1 … ν7
μ0 0 4 8 … 28 μ4 60 56 … 32
μ1 1 5 9 … 29 μ5 61 57 … 33
μ2 2 6 10 … 30 μ6 62 58 … 34
μ3 3 7 11 … 31 μ7 63 59 … 35
```
31 = (μ3, ν7) 32 = (μ4, ν7)——相邻两个块共用同一条 B 列带ν7窗口切换几乎零增量对比朴素行优先Ñ=16 一波横跨 2 A 行块 + 16 B 列带足迹 (2·M^t + 16·N^tK·dtype滑窗为 (4·M^t + 8·N^tK·dtype——M^tN^t 时足迹缩小 1/3
**窗内为什么不蛇形**对上例中" 3=(μ3,ν0) 4=(μ0,ν1) 而非 (μ3,ν1)"的说明蛇形的收益来自"相邻遍历段共享边界数据"要分两种边界看
* **窗内列间边界**ν0ν1相邻两段共享的是同一组 A 行块W 它们在整个窗口期间**全程驻留 L2**无论按什么顺序扫工作集不变——窗内蛇形零收益
* **窗口行边界**窗口0窗口1A 行整体换血μ0..3 μ4..7此时 B 列带的连续性决定换血成本——不蛇形则下一窗口从 ν0 开始LRU 上最久未用早已被挤出 L2 的冷带蛇形则延续上一窗口末尾的 ν7最热线带)。**蛇形只标在窗口行号上**源码 `BatchMatMulAswBlock::UpdateBasicIndex` `rowIdx` 为奇时 n 反向窗内 m 最快序不反向正是这个收益结构的直接实现
**3、L2 切分(工作集超 L2 时)**
**切的是什么**L2 切分切的是**输出平面**—— M×N 平面切成 mL2TileNum × nL2TileNum 个大矩形块每块 = 若干基本块的集合),使"该块所需的 A 行带 + B 列带"输入工作集 L2 可用读入空间块内所有输出基本块算完再进下一块输入只在跨块时换一次
**为什么需要它**滑窗压缩的只是"同一波"的足迹若整个工作集超 128MB L2跨波次复用落空——上一波窗口的 A 行早被挤出下一波又得回 GM L2 **读写共用**输出经 fixpipe 写出时若驻留 L2dirty会压缩读入可用空间若直写 GM则占用与读共享的 1.6TB/s 总线所以 L2 切分必须与写出策略联合决策记输入总量 $S_{in} = B(MK+KN)\cdot\text{dtype}$输出总量 $S_{out} = B \cdot MN \cdot outB$。
**两个不变量**一切分析的起点
* GM 流量下界 $= S_{in} + S_{out}$输入至少读一遍输出最终至少要写一遍到 GM L2 策略无关
* L2 读入可用空间$L2_{read} = L2 - S_{out}^{resident}$$S_{out}^{resident}$ 为驻留 L2 的输出量)——写出驻留 L2 会压缩读入空间这是写出策略影响读入复用的通道
**重复读倍率**$r_{in}$ = GM 输入流量 / $S_{in}$。$r_{in} = 1$ 表示每个输入数据从 GM 只读一遍后续复用全在 L2 命中)——这是 GM 输入流量的下界L2 管理的全部目标就是让 $r_{in}$ 尽量接近 1
**先判定写出会不会 Bound**平均写出带宽需求
$$
BW_{out} = \frac{S_{out}}{T_{MMAD}} = \frac{B \cdot MN \cdot outB}{2BMNK\,/\,(C \cdot Q_{16})} = \frac{C \cdot Q_{16} \cdot outB}{2K}
$$
只与 KoutB 有关K 越小单位时间输出越密)。BF16 输出C·Q₁₆=432 TFLOPSK=512 844 GB/sK=256 1.69 TB/s已超 GM 总线——此时**任何策略都写出 Bound**L2 缓冲只能削峰fixpipe 5.2TB/s L2 吸收突发平均速率仍受总线限制应预期 Fixpipe 成为 $T_{total}$ max
**分场景决策**
**场景 A$S_{in} + S_{out} \le L2$(全驻留)**输入读一遍$r_{in}=1$输出驻留 L2dirty异步回写 GM——写出走 5.2TB/s L2 写口不与读争也削平了 GM 写突发无需切分
**场景 B$S_{in} \le L2$ 但 $S_{in} + S_{out} > L2$(输入能驻留,加上输出超了)**策略**输入驻留输出直写 GM**。理由链
1. $S_{in} \le L2$ 全部输入可驻留 L2跨波次复用全部命中 $r_{in} = 1$GM 输入流量达到下界 $S_{in}$
2. 输出在本算子内只写不读零复用收益若输出也驻留 L2dirty超出 L2 的部分会把输入挤出——被挤出的输入后续得回 GM 重读 $r_{in} > 1$GM 流量超出下界;
3. 故让输出直写 GMfixpipe L0C→GM不占 L2把 128MB 全部留给输入,保住 $r_{in} = 1$——GM 总流量保持下界 $S_{in} + S_{out}$
4. 代价是输出即刻占用 GM 写带宽(与读共享总线),须校验总线不爆:$(S_{in} + S_{out})/T_{MMAD} \le W_{GM}$。
B=8、M=N=4096、K=512、BF16——$S_{in}$≈67MB ≤ L2$S_{out}$≈268MB 直写 GMT_MMAD≈318µs总流量速率 (67+268)MB/318µs ≈ 1.05TB/s < 1.6TB/s ✓。
**场景 C$S_{in} > L2$(输入本身超)**必须 L2 切分输出直写 GM 以最大化 $L2_{read}$切分数满足
$$
mL2TileNum \times nL2TileNum \;\ge\; \frac{S_{in}}{L2_{read}}
$$
每块输入工作集 $L2_{read}$逐块计算——块内滑窗复用充分块间只发生一次性换入块内分配用**错位分核**对角线分配线性块号先取 mn 方向叠加随块号递增的相位偏移使同一时刻各核落在 M×N 平面的不同对角线上——避免多核同一拍并发读同一行 A / 同一列 B 的同一地址同地址并发读会串行化等效带宽打折)。8 4×4=16 个基本块k0~k7 为核号
```
行优先(不错位): 错位分核(对角线):
n0 n1 n2 n3 n0 n1 n2 n3
m0 k0 k1 k2 k3 m0 k0 k4 . .
m1 k4 k5 k6 k7 m1 . k1 k5 .
m2 . . . . m2 . . k2 k6
m3 . . . . m3 k7 . . k3
同一波A 行带 m0 被 k0~k3 同读 同一波:每行带、每列带
4 路同地址冲突) 最多 2 核同读(冲突 4→2
```
冲突度量与优选规则
$$
transConflict = \max\big(\lceil C / mCnt \rceil,\; \lceil C / nCnt \rceil\big) \le 6
$$
即同一时刻并发核访问同一 A/B 块的最大冲突数不超过阈值经验值 6切分方案中优先选尾波不满载占比小拖尾 < 一半遍历大方向由 calOrder 决定0=M 优先1=N 优先按形状选共享矩阵更能驻留 L2 的方向B=64、M=N=2048、K=1024、BF16——$S_{in}$≈537MB > L2输出直写$L2_{read}$=128MB切 3×2=6 块(每块输入约 89MB ≤ 128MB总流量约 1.07GBT_MMAD≈1.27ms,速率 844GB/s < 1.6TB/s ✓。
补充若输出会被后续算子立即消费融合场景输出驻留 L2 让下游读命中场景 B/C 的策略反过来本文按单算子边界分析
**4、核内 tiling**$M^t N^t \cdot 4\text{B} \cdot DB \le L0C$$M^t K^t \cdot \text{dtype} \cdot 2 \le L0A$、$K^t N^t \cdot \text{dtype} \cdot 2 \le L0B$内轴按 dValue 256B/512B 对齐L1 按容量开双缓冲余量充足开 4 buffer
**5、内部特化参数极限不是独立分支**单边无 batch 且该侧矩阵小$M \le 256$、$MK\cdot\text{dtype}\cdot 2 \le L1$、对侧每核循环 4 时小侧整个常驻 L1只搬一次L1 全载)。
**6、降核模式实现**tiling `usedCoreNum = ⌈P⌉`不强制 C基本块在 L0C 容量内取最大$M^t N^t \cdot 4\text{B} \le L0C$每核按标准核内流水L1L0CubeL0CFixpipe处理自己的输出块核间无共享无依赖无需 swizzle L2 切分降核后 GM 并发搬移核数若 < minCoreNum带宽利用率上限被压低——这正是降核区 case 时延的瓶颈所在也是"时延绝对值小不再继续优化"的定量注脚
---
## 九、特殊分支
* **K=0**无任何计算C = bias 0 AIV 写值
* **K=1**:退化为逐元素乘 `C = A ⊙ B`无累加深度Cube 16×16×16 粒度浪费 15/16 AIV 向量通路GMUBMulGM优于 Cube 通路触发需 $B \ge 2 \times 64$AIV 核数×2 UB 乒乓且单 batch 输入输出能驻留 UB
---
## 十、case 遍历:各分支的覆盖区域
### 方法论说明
**采样方式**B [1, 2048] 全量遍历2048 个值M/N/K [1, 10240] 对数网格采样 60 /值按指数增长1, 2, 3, 5, 7, 10, 14, 19, 26, 35, ...)。 case 3.2 亿耗时约 4 分钟
**为什么不做全量遍历**全量 = 2048 × 10240³ 2.2×10¹⁵ casePython 分类器约需 1400 万小时C 实现约需 6 万小时——完全不可行对数采样在小值区密集大值区稀疏恰好覆盖了分支边界集中的区域
**分布依赖测度**对数均匀采样和线性均匀采样给出的分支占比**不同**。对数采样在小值区密集特殊分支K=0/1、降核 ASWP )、StreamKK 大但 M/N 的占比被放大线性采样被大 shape 主导M/N/K > 512 占 [1,10240] 的 95%+ASW_Basic 占比显著升高。**本文遍历的目的是验证覆盖性(无空洞),不是统计真实工作负载的分布。**
### 分支覆盖统计对数采样B 全量 2048M/N/K 60 点/维,共 3.2 亿 case
| 分支 | case 数 | 占比 | B 范围 | 区域特征 |
|---|---|---|---|---|
| ASW_Basic | 1.75 亿 | 54.1% | 2 ~ 2048 | 通用B<C PC BC L1 四形态不满足M/N |
| MergeBatch | 6303 | 19.5% | 97 ~ 2048 | $b_{core}\ge 4$ $MN \le 8192$ 等五条全过 |
| 降核 ASW_Basic | 4051 | 12.6% | 2 ~ 2048 | P<C K 不满足 StreamK 阈值 只用 P |
| IterBatch | 3804 | 11.8% | 32 ~ 2048 | BC负载均衡L1 四形态之一满足 |
| 特殊分支 | 597 | 1.9% | 任意 | K=0 / K=1 |
| StreamK | 25 | 0.08% | 2 ~ 128 | P<C/2 K8192 |
| 转Matmul | 15 | 0.05% | B=1 | 单边 batch=1 |
**对照:线性等距采样**M/N/K 步长 256B 全量 1.3 亿 case ASW_Basic 占比升至 92.1%MergeBatch 降至 3.6%——因为线性采样被大 shape 主导两种测度的结论一致**无空分支无覆盖空洞**只是占比不同
### IterBatch 四形态命中分布(对数采样)
| 形态 | 命中数 | 占比 | 说明 |
|---|---|---|---|
| b) batch 乒乓 | 2684 | 70.5% | 最多B 大且单 batch 较小 |
| d) 两侧切 K | 741 | 19.5% | 次之K 可切段的通用兜底 |
| c) 一侧驻留+对侧切 K | 370 | 9.7% | 单侧可驻留 b_core2 的半预算预取档 |
| a) batch 全驻留 | 9 | 0.2% | B=C 附近的窄区 |
### 典型边界 case
| B | M | N | K | 分支 | 说明 |
|---|---|---|---|---|---|
| 1 | 2048 | 2048 | 2048 | 转Matmul | batch Matmul |
| 128 | 64 | 64 | 512 | **MergeBatch** | 五条全过$b_{core}$=4MN=4096≤8192单核搬移 512KB480KBAI=64<304 |
| 128 | 64 | 64 | 256 | IterBatch | 与上行仅 K 不同单核搬移 256KB < 480KB条件 3 不满足 IterBatch形态 b |
| 512 | 128 | 128 | 128 | IterBatch | MN=16384 > 8192MergeBatch 条件 2 不满足 → 落 IterBatch |
| 32 | 4096 | 4096 | 4096 | ASW_Basic | L1 四形态均不满足M/N 太大),切 M/N |
| 2 | 8192 | 8192 | 1024 | ASW_Basic | B<CP=2048 32 |
| 16 | 256 | 256 | 128 | 降核 ASW | P=4 < 32 K=128 不满足 StreamK 4 其余闲置 |
| 4 | 128 | 128 | 10240 | StreamK | P=0.25 < 32K8192 |
| 2048 | 1024 | 1024 | 512 | IterBatch | batch形态 b |
| 8 | 512 | 512 | 512 | ASW_Basic | B<CP=32 恰好满核 |
| 64 | 64 | 64 | 8192 | IterBatch | M×N K 形态 d |
### 遍历结论
1. **七个分支全部有真实 case 命中**无空分支覆盖矩阵无空洞P<C K 小的残余由降核 ASW_Basic 兜底——此时时延绝对值小调度开销主导分支选择不敏感
2. **MergeBatch 的区域由条件 2$MN \le 8192$)与条件 3min_DatamountPerCore夹出** M×N 且单核搬移量足够的大 batch case两个条件缺一不可典型分界对照B=128/M=N=64 K=256 单核搬移 256KB 不达标落 IterBatchK=512 512KB 达标进 MergeBatch
3. **IterBatch 与 ASW_Basic 的分界就是 L1 四形态是否满足** batch 输入 $(MK+KN)\cdot\text{dtype}$ 相对 L1 的比例决定归属——这正是"核内零重复读"原则的定量体现
4. **StreamK 的区域为 P<C/2 且 K≥8192**B M/N K 大的"细长" caseC/2 P < C K 大的 case 由降核 ASW_Basic 承接 2 K 会超核数不切又不满核不如直接用 P
5. **降核 ASW_Basic 是 P<C 且 K 小区域的理性归宿** 12.6%并行度凑不满 K 又不划算时只用 P 个核每核一个 L0C 满载输出块比强行碎切tile 跌破搬移效率下限更快