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

470 lines
24 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 算子特性分析v0.5
> 基于 issue#3v0.3)扩展补全。所有分支的进入条件只出现 B/M/N/K 与芯片规格参数,每条条件附简要解释。
> 目标芯片:昇腾 950PR / DV100 同档DAV_3510
---
## 算子功能与接口说明
算子功能:完成带 batch 的矩阵乘计算。
算子输入:
* 左矩阵A 矩阵):`[BatchA, M, K]`、数据类型 dtype、layout典型 ND
* 右矩阵B 矩阵):`[BatchB, K, N]`、数据类型 dtype、layout典型 ND
* 偏置 bias维度固定 `[B, 1, N]`、数据类型 dtype、layout固定 ND可为空
算子输出输出矩阵C 矩阵):`[BatchC, M, N]`、数据类型 dtype、layout典型 ND
计算公式:`C = A @ B + bias`
其中 A、B 输入维度典型为 3 维,最后两维做矩阵乘计算。例如 A、B 输入维度分别为 (B,M,K)、(B,K,N) 时C 维度为 (B,M,N)。bias 是维度为 (B,1,N) 的向量。B 为矩阵乘法的 batch 数M 为 A 的行数和 C 的行数N 为 B 的列数和 C 的列数K 为 A 的列数和 B 的行数。
---
## 符号与芯片参数约定
后文所有分支条件只使用 case 形状参数B、M、N、K、dtype与下列芯片规格参数
| 符号 | 含义 | 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 | 芯片算存比平衡点BF16/FP16 | ≈607.5 FLOP/元素 |
| min_TileSize | 单次搬移效率下限 | 16KB |
| min_DatamountPerCore | 单核搬移总量下限 | 480KB |
| minCoreNum | 尾波活跃核数下限 | ≈0.8·C = 26 |
| k_thr | K 向搬移 dValue 下限 | 32B/dtypeBF16 为 16 元素) |
> 以上经验常数均为该档芯片实测值;换芯片时逻辑结构不变,只换常数表。
---
## BMM 算子最优实现分析
### 最优软件实现设计的系统推导
#### 如何理解性能最优
NPU 上 BMM 的执行是核内多级硬件流水的并行——Cube 计算MMAD、GM/L2→L1 搬移MTE2、L1→L0 搬移MTE1、L0C 写出Fixpipe多核并行时各流水级时延可被双缓冲double buffer等机制相互掩盖最终
$$
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 模型。
#### 实现本质逻辑
BMM 在 NPU 上实现的本质是把参与计算的数据分块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 个维度B、M、N、K。核间怎么分这 4 个维度,就是分支划分的第一性问题(核内分块是第二性问题,属于各分支内部的 tiling
从"读入 / 计算 / 写出"三个视角考察每个维度的核间切分特征(这是后续一切推导的基石):
| 切分维度 | 读入特征 | 计算特征 | 写出特征 |
|---|---|---|---|
| 切 B | 每个数据块只被固定的 1 个核读取,核间零重复读 | 每个输出块由 1 个核独立完成,无核间依赖 | 只写最终结果,无中间结果 |
| 切 M / 切 N | **切 M 则同一右矩阵块被多核重复读;切 N 则同一左矩阵块被多核重复读** | 每个输出块由 1 个核独立完成,无核间依赖 | 只写最终结果,无中间结果 |
| 切 K | 每个数据块只被固定的 1 个核读取,零重复读 | 每个输出块由多核共同完成,存在核间依赖 | **有中间结果写出,需核间 Reduce 归约** |
不同切分差异的根本原因:
* B 维在数学上独立BMM 语义就是逐 batch 独立矩阵乘),所以切 B 天然零重复、零依赖;
* K 维有 L0C 累加机制:核内切 K 时,切 K 后多轮 mmad 在 256KB 的 L0C 上原地累加cmatrixInitVal=false中间结果不出核。一旦把 K 切到核间,单核的 L0C 装不下"别的核算的 K 段",部分和必须写出到 GM/L2 workspace再由 AIV 归约——切 K 是唯一同时破坏"累加不出核"和"输出独占"两条性质的切法。
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 种是完备的。按切分特征分组:
| 组 | 组合 | 共同特征 | 优化重心 |
|---|---|---|---|
| 只切 B | {B} | 零重复读,读写数据量固定 | 访存 Bound搬移效率高计算 Bound计算效率高 |
| 切 B + M/N 切分,不切 K | {B,M},{B,N},{B,M,N},{M},{N},{M,N} | 可能有重复读 | 访存 Bound重复读尽量少 + 搬移效率高;计算 Bound计算效率高 |
| 含 K 切分 | {B,K},{B,M,K},{B,K,N},{B,M,K,N},{K},{M,K},{K,N},{M,K,N} | 可能有重复读;有中间结果写出 + 归约 | 计算效率高,且归约引入的额外 MTE2/Fixpipe 时延不能成为新瓶颈 |
15 种组合的代价结构只由两个布尔特征决定——是否含 K、是否含 M/N。
三个维度的"核间切分价格"严格排序cost(切 B) = 0 < cost( M/N) cost( K)
* B 免费零重复读零依赖零中间写出
* M/N 廉价但有价共享矩阵被重复读但若共享部分能驻留 L2128MB重复读以 5.2TB/s 命中 L2 而非 1.6TB/s GM则代价大部分被 L2 吸收配合 swizzle执行顺序编排压缩同时活跃的数据集代价进一步压低
* K 昂贵归约流量 $T_{Reduce} \propto grid_K \times$ 输出量且引入核间同步——这是结构性代价L2 吸收不掉
"价格表"不是经验 BMM 语义 + L0C 累加机制 + L2/GM 带宽结构三条事实的推论整条分支决策树就是一句话按价格从低到高购买并行度买不够才加价
### BMM 算子软件分支推导
**1、问题规约能降维就不在 BMM 本体里解决)**
* BatchA = 1 BatchB = 1BMM 可通过维度折叠**转化为普通 Matmul**直接复用 Matmul 的成熟优化体系tilingL2 切分全载不必在 BMM 框架内重新发明轮子 Matmul
* 退化 caseK=0 无计算K=1 无累加深度 Cube 完全或几乎无用改走 AIV 向量通路——这属于"计算通路选择"是正交于切分的前置判断可称为特殊分支
**2、先买免费的 B 维度**
* B 可满足多轮都尽量填满核
* 如果单 Batch M×N 够大能开出大 tileL0C 利用率高Cube 喂得饱)→ 每核逐个 batch 做完整 Matmul 就是最优任何额外切分只增代价可称为 IterBatch 分支
* 如果单 Batch M×N 很小把多个 batch 在核内合并成大 tile 计算[bM,K]@[K,bN]取块对角线输出用冗余算力换 Cube 利用率与搬移效率可称为 MergeBatch 分支
**3、B 维度买不满核,加点价买廉价的 M/N 维度切分**
* 优先切 B 后再切 M/N或混合切 MN 引入的共享矩阵重复读交给 L2 + swizzle 吸收可称为 ASW_Basic 分支
**4、免费和廉价维度 B、M、N 都买不满核,才考虑加价买昂贵的 K 维度切分**
* 用核间规约代价换并行度收益可称为 StreamK 分支
由此推导出 6 大分支**转Matmul特殊分支MergeBatchIterBatchASW_BasicStreamK**。
> 各分支的进入条件给出的是"主场";主场之间存在重叠区(如 B ≥ C 且 M×N 中等时 MergeBatch 与 IterBatch 都合法),重叠区的归属由端到端时延模型 $T_{total}$ 仲裁,分支体系保证候选集完备无冗余。
---
## 可转 Matmul 分支
### 进入分支条件
$$
BatchA = 1 \;\lor\; BatchB = 1
$$
解释单边 batch=1 BMM 与普通 Matmul 在数学上只差一个维度标签无需在 BMM 框架内重新发明轮子
### 实现方案
对于 BatchB = 1左矩阵 `[B, M, K]` batch 维与 M 维在 ND 布局下内存相邻紧排直接视图为 `[B·M, K]`输出 `[B·M, N]` `[B, M, N]` 的内存布局逐元素一致无输入重排无输出 Split可直接转 Matmul 无任何代价
对于 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**。
此时当 A 矩阵比较小时$MK \cdot \text{dtype} \le L1$优先考虑将 A 矩阵加载到每个核的 L1然后每个核均匀读取 B 矩阵完成全部计算此时无需输入/输出重排的额外开销
A 矩阵较大时可将 BatchA==1 扩展到 BatchA==BatchB广播然后分别按 BMM 其他分支与"B 折叠转 Matmul + 重排"预估时延择优选型
---
## MergeBatch 分支
每个核负责多个 Batch Matmul 计算核间无需同步或通信假设单核每次要完成 b Batch Matmul 计算单核计算时将 [b,M,K]@[b,K,N]=[b,M,N] 转换合并成 [bM,K]@[K,bN]=BlockTrace([bM,bN])=[b,M,N]。所谓 BlockTrace 指以 [M,N] block 粒度将结果矩阵的块对角线取出作为输出交叉项不同 batch A B 的乘积被算出但丢弃浪费比例 (b1)/b——进入该分支的 case 必然是访存 Bound条件 5 保证浪费的算力被搬移时延掩盖
### 进入分支条件
进入 MergeBatch 分支需同时满足以下条件b0 为单次合并数下限b0 2
**1、batch 关系与每核份额**
$$
BatchA = BatchB \;\;\text{}\;\; b_{core} = \frac{B}{C} \ge 2\,b_0
$$
解释无广播才能逐 batch 对应合并每核至少分到 $2b_0$ batch——$b_0$ "合并搬移有收益"的最小合并数经验值 4 $b_{core} \ge 4$ 时至少能合并 2 2 组起步才能构成组间乒乓流水
**2、L0C 容量**
$$
2 \cdot (b_0 M)(b_0 N) \cdot 4\text{B} \le L0C
$$
解释合并 $b_0$ batch 的输出块 $[b_0 M, b_0 N]$FP32 累加双缓冲两份必须放得下 256KB L0C连最小合并都放不下合并无从谈起
**3、单核搬移总量**
$$
b_{core} \cdot (MK + KN) \cdot \text{dtype} \ge 480\text{KB}
$$
解释单核搬移数据总量不足时 GM 带宽利用率上限被压低经验约束)。
**4、搬移 tile 大小**
$$
\max(MK,\; KN) \cdot \text{dtype} \ge 16\text{KB}
$$
解释 batch 单矩阵的最大连续搬移块须达到单次搬移效率下限合并只是在此之上进一步放大
**5、访存 Bound算力浪费可被掩盖**
$$
\frac{2MN}{M+N} < \frac{R}{b_0}
$$
解释合并把单次计算的算存比放大 $b_0$ 倍后仍须低于芯片平衡点 R保证瓶颈留在搬移侧——冗余算力被搬移时延掩盖而不是反过来成为新瓶颈
### 实现方案
确定 Tiling 参数重点是确定 $b_{L0}$、$k_{L1}$、$b_{L1}$。
**Step 1基于 L0C 容量 + 访存 Bound 约束,先确定每次计算的合并数 b**
$$
b^2 \le \frac{L0C}{2 \cdot MN \cdot 4\text{B}} \;\Rightarrow\; b < b_i
$$
$$
\frac{2MN}{M+N} < \frac{R}{b} \;\Rightarrow\; b < b_{ii}
$$
$$
b = \min(b_i,\; b_{ii},\; b_{core}),\quad b_{L0} = b
$$
b 尽量取 $b_{core}$ 的因子每次计算的合并数均匀一致负载与功耗更优)。
**Step 2基于 $b_{L0}$ 和 L0A/L0B 确定 $k_{L0}$**
$$
2\,b M \cdot k_{L0a} \cdot \text{dtype} \le L0A,\qquad 2\,b N \cdot k_{L0b} \cdot \text{dtype} \le L0B
$$
$$
k_{L0} = \min\big(k_{L0a},\; k_{L0b},\; 32\text{B}/\text{dtype}\big)\;\text{向下 16 对齐}
$$
解释L0A/L0B 64KB双缓冲两份装入合并后 $bM$ $bN$ × $k_{L0}$ fractal第三项保证 K 向内轴 dValue 32B 的搬移下限
**Step 3基于 $k_{L1}$ 和 L1 容量确定 $b_{L1}$**
$$
k_{L1} \ge \min\big(k_{L0\_max},\; 128\text{B}/\text{dtype}\big)
$$
$$
2 \cdot b_{L1\_max} \cdot (M k_{L1} + k_{L1} N) \cdot \text{dtype} \le L1
$$
$$
b_{L1} = \min(b_{L1\_max},\; b_{core})
$$
解释$k_{L1}$ GML1 K 向粒度须满足 128B 对齐dValue 效率L1 双缓冲两份每份驻留 $b_{L1}$ batch AB 各一块要求 $b_{L1} \ge b$L1 驻留组不小于单次合并数否则合并断供)。
---
## IterBatch 分支
核间按 B 分核每核 1 个或多个 batch核内逐个 batch 分别执行标准 Matmul 分块计算无算力浪费无跨 batch 依赖" B"最朴素的形态
### 进入分支条件
进入 IterBatch 分支需同时满足以下条件
**1、batch 关系与每核份额**
$$
BatchA = BatchB \;\;\text{}\;\; b_{core} = \frac{B}{C} \ge 1
$$
**2、负载均衡**
$$
B \bmod C = 0 \;\;\lor\;\; B \bmod C \ge minCoreNum
$$
解释 B 零共享零依赖唯一系统性风险是负载不均B 整除核数时完全均衡不整除时要求尾波中活跃的核数不少于 minCoreNum(≈0.8C=26保证尾波也有足够核并发以维持 GM 带宽利用率
**3、L1 容量约束(五选一)——核心要求:单核数据不重复读**
注意IterBatch 能否进入**不取决于算存比判定**。即使 case 本身是计算 Bound只要 L1 放不下单核要处理的完整输入MN 维度的 A/B 数据就会产生跨 batch 的重复读额外搬移可能把算子重新拖回访存 Bound所以进入条件必须直接由 L1 容量刻画
a) 单核单 batch 完整驻留
$$
b_{core} = 1 \;\;\text{}\;\; (MK + KN) \cdot \text{dtype} \le L1
$$
解释每核 1 batch左右矩阵同时驻留 L1零重复读
b) 单核多 batch 乒乓
$$
b_{core} > 1 \;\;\text{且}\;\; 2(MK + KN) \cdot \text{dtype} \le L1
$$
解释L1 同时放下 2 个 batch 的输入,构成 batch 间双缓冲流水。
c) 单 batch 放不下:一侧完整驻留、另一侧按 Step 切分:
$$
b_{core} = 1,\;\; (MK + KN) \cdot \text{dtype} > L1,\;\; \big(MK + \tfrac{KN}{Step}\big) \cdot \text{dtype} \le L1 \;\;\lor\;\; \big(\tfrac{MK}{Step} + KN\big) \cdot \text{dtype} \le L1
$$
解释Step 为大于 1 的正整数。左(或右)矩阵完整驻留 L1、只搬一次或左矩阵按 K或 M切 Step 段流水搬入——驻留侧零重复读,切分侧重复读 M或 N维但每段仍整块连续。
d) 多 batch 时 (c) 的乒乓版本(容量预算减半):
$$
b_{core} > 1,\;\; (MK + KN) \cdot \text{dtype} > \frac{L1}{2},\;\; \big(MK + \tfrac{KN}{Step}\big) \cdot \text{dtype} \le \frac{L1}{2} \;\;\lor\;\; \big(\tfrac{MK}{Step} + KN\big) \cdot \text{dtype} \le \frac{L1}{2}
$$
e) 左右都按 K 切分:
$$
\big(M \cdot \tfrac{K}{Step} + \tfrac{K}{Step} \cdot N\big) \cdot \text{dtype} \le L1
$$
解释:两侧矩阵都装不下时,统一按 K 切 Step 段A/B 成段配套搬入。
**4、Step 切分后的带宽效率**
(c)(d)(e) 切分后的每个搬移分块须满足:
$$
\text{tile} \ge 16\text{KB} \quad \text{且} \quad \text{dValue} \ge 128\text{B}
$$
解释:切分是把粒度切小,必须守住搬移效率下限,否则切分本身把带宽打崩。
### 实现方案
**情形 (a)**:每核 1 batch 直接搬入 L1。L1→L0 时先看 L0C 能否放下完整单 batch 输出 M×N
```
if (L0C >= M*N*4B): # L0C 放得下完整输出
BaseM = M; BaseN = N
BaseK = min(align(L0A/M, 16), align(L0B/N, 16)) # 只切 K
else: # L0C 放不下,按较小维切
if M < N:
BaseM = align(M, 16)
BaseN = floor(L0C/4B / BaseM)
BaseK = min(floor_align(L0A/BaseM, 16), floor_align(L0B/BaseN, 16))
else:
BaseN = align(N, 16)
BaseM = floor(L0C/4B / BaseN)
BaseK = min(floor_align(L0A/BaseM, 16), floor_align(L0B/BaseN, 16))
```
**情形 (b)**L1 放下 2 个 batch 则按 batch 做 double buffer核内 GM→L1→L0→Cube→L0C→GM/L2 流水。L1→L0 分块:
```
if (L0C >= 2*M*N*4B): # 双 buffer 放得下两份完整输出
BaseM = M; BaseN = N
BaseK = min(floor_align(L0A/M, 16), floor_align(L0B/N, 16))
else:
if M < N:
BaseM = align(M, 16)
BaseK = min(floor_align(L0A/2/BaseM, 16), K)
BaseN = max(floor_align(L0C/2/4B/BaseM, 16), floor_align(L0B/2/BaseK, 16))
else:
BaseN = align(N, 16)
BaseK = min(floor_align(L0B/2/BaseN, 16), K)
BaseM = max(floor_align(L0C/2/4B/BaseN, 16), floor_align(L0A/2/BaseK, 16))
```
**情形 (c)**:每核 1 batchL1 放完整一侧矩阵 + 另一侧的一部分。假设 L1 放完整左矩阵和部分右矩阵,关键是确定右矩阵搬入的 K 向长度:
$$
k_{L1\_b} = \min\!\Big(\frac{L1 - MK \cdot \text{dtype}}{N \cdot \text{dtype}},\; K\Big)
$$
fixpipe 应开 unitflag单侧驻留场景下输出通路按单元化组织。情形 (d)(e) 同理,按各自容量预算计算 Step 与分块。
---
## StreamK 分支
### 进入分支条件
**1、并行缺口存在**B/M/N 用尽仍填不满核):
$$
P = B \cdot \Big\lceil \frac{M}{16} \Big\rceil \cdot \Big\lceil \frac{N}{16} \Big\rceil < C
$$
解释 Cube 最小分形16×16为粒度B×M×N 三维最多切出 P 个互不依赖的输出块P < 32 意味着不切 K 必有核闲置
**2、K 足够长**归约代价可接受设核间切 K 的份数为 $grid_K$
$$
\frac{K}{grid_K} \ge 256 \quad\text{}\quad K \;\gtrsim\; grid_K^{\,2} \cdot \theta,\;\; \theta \approx 1.7\times10^{3}
$$
解释第一式保证单核 K 段不太碎核内 tiling 效率不崩第二式来自 $T_{MMAD/core} \ge \alpha \cdot T_{Reduce}$安全系数 α10每核计算时延 $MNK/grid_K$除以单核 Cube 速率归约时延 $grid_K \cdot MN \cdot 4\text{B}$除以 GM 带宽)——归约流量随 $grid_K$ 线性涨每核收益也随 $grid_K$ 线性涨相抵后对 K 的要求随 $grid_K$ **平方**增长数值上$grid_K$=2 K6.8K4 K27K8 K108K32 K1.7M仅极端 case)。
### 实现方案
**核间组织**先按 B/M/N 切出 P 个输出块再把剩余核预算折成 K 向份数对每个 batch
$$
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$。每个输出块由 $grid_K$ 个核组成的归约组共同计算组内核 c 负责 K $[c \cdot K/grid_K,\; (c{+}1) \cdot K/grid_K)$$singleCoreK = K / grid_K$。
**核内流水**每核对自己的 K 段做标准分块流水MTE2L1L0mmad段内多轮在 L0C 原地累加段算完后部分和经 Fixpipe 写出
**归约**两种方式
* **workspace + AIV 归约确定性**部分和写入 GM workspace每核一块 256×256×4B 缓冲另加 20MB 核间通信区 AIV 读出各段并累加输出——AIC:AIV=1:2 配比下 2 AIV 伺候 1 AIC 的部分和流
* **AtomicAdd非确定性**部分和直接原子累加到输出 GM省一遍读回但归约顺序不定确定性等级 > 1 的场景禁用。
**参数搜索**$grid_K$ 从 2 起按 2 的幂递增,取同时满足条件 2 两式的最小值(归约代价最小);若到 $grid_K = blocksPerBatch$ 仍不满足条件 2则该 case 不宜 StreamK退而接受降核的部分闲置。
---
## ASW_Basic 分支
### 进入分支条件
**1、并行度补齐**B 买不满核时M/N 平面能补上):
$$
P = B \cdot \Big\lceil \frac{M}{M^t} \Big\rceil \cdot \Big\lceil \frac{N}{N^t} \Big\rceil \ge C,\qquad M^t N^t \cdot 4\text{B} \le L0C,\;\; M^t, N^t \ge 16
$$
解释:基本块粒度 $M^t \times N^t$ 受 L0C 容量封顶(最小 16×16按此粒度 B×M×N 能切出至少 C 个独立输出块,则切 M/N 的并行度够用。
**2、典型进入路径**$B < C$ B 买不满核 $B \ge C$ IterBatch/MergeBatch 条件不满足L1 驻留失败负载不均MergeBatch 上下限无交集时的兜底 batch 结构限制——交叉广播 case 也落入本分支
解释 M/N 的固有代价是共享矩阵被多核重复读但共享部分若能驻留 128MB L2重复读以 5.2TB/s 命中 L2 而非 1.6TB/s GM代价大部分被吸收配合 swizzle 压缩同时活跃的工作集代价进一步压低
### 实现方案
**1、核间切分维度选择按共享代价从低到高**
* ** B**$B \ge C$零共享永远先试
* ** M**右矩阵 [K,N] 被所有核共享 $KN \cdot \text{dtype} \le L2$ 则驻留 L2 GM 重复读
* ** N**对称左矩阵 [M,K] 共享驻留
* **混合切**B×MM×N 双向共享 swizzle + L2 切分管理
* **降核**P 远小于 C K 也不满足 StreamK 条件时宁可部分核闲置 case 时延绝对值小调度开销反而主导)。
**2、swizzleASW 滑窗蛇形**M 向按窗口 W 分组窗内 N 向蛇形遍历偶数窗行正向奇数窗行反向
$$
W = \max\{\,d \mid d \mid C,\; d \le \lfloor\sqrt{C}\rfloor\,\} \quad (C{=}32 \Rightarrow W{=}4)
$$
数学效果同一时刻 C 个核的活跃工作集被压缩到"W A 行块 + 一条 B 列块带"L2 足迹最小共享读取基本命中 L2窗口取 $\lfloor\sqrt C\rfloor$ 的最大因子窗越接近方形A/B 两侧足迹之和越小且因子性保证整窗被核数均分窗口边界不碎
**3、L2 切分**工作集超过 128MB 时按 mL2TileNum × nL2TileNum 切块每个 L2 块内错位分核对角线分配避免多核同时抢同一地址的读读冲突并优先选拖尾小的方案
**4、核内 tiling**baseM/baseN L0C 容量$M^t N^t \cdot 4\text{B} \cdot DB \le L0C$与计算访存比$1/M^t + 1/N^t$ 越小越接近 Cube Bound联合选取优先整除 MN 减少尾块baseK L0A/L0B 反推$M^t K^t \cdot \text{dtype} \cdot 2 \le L0A$$K^t N^t \cdot \text{dtype} \cdot 2 \le L0B$内轴对齐 128B/256BL1 按容量开双缓冲余量充足时开 4 buffer
**5、内部特化参数极限不是独立分支**
* **L1 全载**单边无 batch 且该侧矩阵小 BatchA=1 $M \le 256$、$MK \cdot \text{dtype} \cdot 2 \le L1$且对侧循环轮数足够$\ge 4$/把小侧矩阵整个常驻 L1只搬一次——搬运次数从"每基本块一次"降为"整个 kernel 一次"
* **广播驻留**交叉广播时对广播侧做 L1/L2 驻留共享关系与切 M/N 同构
---
## 特殊分支
**K = 0**无任何计算C = bias 0 AIV 写值
**K = 1**退化为逐元素乘 `C = A ⊙ B`无累加深度Cube 16×16×16 粒度浪费 15/16 AIV 向量通路GMUBMulGM优于 Cube 通路
解释这一层与"切分维度"正交是计算通路选择的前置判断——K 退化时 Cube 完全或几乎无用AIV64 每拍 256B纯向量流水更优触发需 batch 足够多(≥ 2×AIV 核数 UB 乒乓且单 batch 输入输出能驻留 UB