diff --git a/BMM/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html b/BMM/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html new file mode 100644 index 0000000..1d32b5c --- /dev/null +++ b/BMM/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html @@ -0,0 +1,524 @@ + + + + + +BMM 算子优化分析 v0.94 — 昇腾 950PR + + + + + +
+

BMM 算子优化分析(v0.94)

+
目标芯片:昇腾 950PR(DAV_3510)。所有分支进入条件只含 case 形状参数(B、M、N、K、dtype)与芯片规格参数。
+
+

一、算子功能与接口说明

+

完成带 batch 的矩阵乘:C = A @ B + bias

+ +
+

二、符号与芯片参数约定

+ + + + + + + + + + + + + + +
符号含义950PR 取值
CAIC 核数(aicNum)32
Q₁₆单核 Cube BF16 峰值算力486/C ≈ 15.2 TFLOPS
Q_AIVAIV 向量求和吞吐(64 核合计)64×128 fp32/拍×1.65GHz ≈ 13.5 Tops/s
L1每核 L1 Buffer512KB
L0A / L0B每核 L0A / L0B64KB / 64KB
L0C每核 L0C(FP32 累加,4B/元素)256KB
L2L2 Cache 容量128MB
W_L2L2 读写带宽5.2TB/s
W_GMGM 带宽(读写共享)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→L1(MTE2)、L1→L0(MTE1)、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 个维度:B、M、N、K。核间怎么分这 4 个维度,就是分支划分的第一性问题(核内分块是第二性问题,属于各分支内部 tiling)。

+

四个维度的核间切分特征(后续一切推导的基石):

+ + + +
切分维度读入特征计算特征写出特征
切 B核间零重复读(每个数据块只被 1 个核读取);核内是否重复读另有条件——若 L1 放不下单 batch 完整的 M、N 维输入(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 L2(5.2TB/s vs GM 1.6TB/s)+ swizzle 大部分吸收;切 K 的归约流量 ∝ grid_K×输出量且引入核间同步,是结构性代价。整条分支决策树就是:按价格从低到高购买并行度,买不够才加价。

+

3.3 分支推导

+
    +
  1. 问题规约:BatchA=1 或 BatchB=1 → 折叠转普通 Matmul(转Matmul);K=0 / K=1 → Cube 无用,走 AIV 向量通路(特殊分支,与切分正交的前置判断);
  2. +
  3. 先买免费的 B:B ≥ C 时切 B 可满核。单 batch M×N 够大 → 逐 batch 算(IterBatch);M×N 太小 → 多 batch 合并成大 tile 算,冗余算力换搬移效率(MergeBatch);
  4. +
  5. B 买不满,加价买 M/N:切 M/N 或混合切,重复读交给 L2 + swizzle(ASW_Basic);
  6. +
  7. B/M/N 都买不满,才买昂贵的 K:核间切 K + 归约(StreamK)。
  8. +
+

由此得 6 大分支:转Matmul、特殊分支、IterBatch、MergeBatch、ASW_Basic、StreamK。重叠区(如 B≥C 且 M×N 中等时 MergeBatch 与 IterBatch 都合法)由端到端时延模型 $T_{total}$ 仲裁;分支体系保证候选集完备无冗余。

+
+

四、可转 Matmul 分支

+

进入分支条件

+
$$ +BatchA = 1 \;\lor\; BatchB = 1 +$$
+

解释:单边 batch=1 的 BMM 与 Matmul 只差一个维度标签,直接复用 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]$。交叉项被算出但丢弃(浪费比例 (b−1)/b)——进入该分支的 case 必然访存 Bound(条件 5 保证),浪费的算力被搬移时延掩盖。

+

进入分支条件(汇总)

+

同时满足(b0 = 单次合并计算的 batch 数下限,b0 ≥ 2):

+
    +
  1. $BatchA = BatchB \;\land\; b_{core} = B/C \ge 2b_0$
  2. +
  3. $2 \cdot (b_0 M)(b_0 N) \cdot 4\text{B} \le L0C$
  4. +
  5. $b_{core} \cdot (MK + KN) \cdot \text{dtype} \ge min\_DatamountPerCore$
  6. +
  7. $\max(MK,\; KN) \cdot \text{dtype} \ge min\_TileSize$
  8. +
  9. $\dfrac{2MN}{M+N} < \dfrac{R_{16}}{b_0}$
  10. +
+

逐条解释

+
    +
  1. batch 关系与每核份额:无广播才能逐 batch 对应合并;每核至少分到 $2b_0$ 个 batch——$b_0$ 是合并搬移有收益的最小合并数(取 2),2 组起步才能构成合并组间乒乓流水(即 $b_{core} \ge 4$)。
  2. +
+

MergeBatch vs IterBatch 分界建模

+

*执行模型*:两分支的核间切分相同——B 维切分到 C 核,每核 $b_{core} = B/C$ 个 batch;核内不切 M/N。核心差异在 GM→L1 搬移粒度

+ +

*符号*:

+ + + + + + + +
符号含义表达式
$k_{L1}$L1 级 K 分块粒度(双缓冲)$\min\big(K,\; L1/(2(M{+}N)\cdot\text{dtype})\big)$
$n_K$K 分块数$\lceil K/k_{L1} \rceil$
$T_{load}$每 K 分块搬移时延$k_{L1}(M{+}N)\cdot\text{dtype}/BW_{pc}$
$T_{comp}$每 K 分块计算时延$2MN \cdot k_{L1}/Q_{16}$
$T_{write}$单 batch 输出写回时延$MN \cdot outB/W_{GM}$
$T_{cmd}$单次 GM→L1 DMA 搬移固定开销描述符配置 + 地址生成 + 突发启动
$BW_{pc}$单核 GM 带宽份额$W_{GM}/C$
+

*端到端时延模型*:L0C 双缓冲使 fixpipe 与 Cube 完全交叠,无 batch 边界同步开销。差异仅来自 GM→L1 搬移次数和 drain 暴露:

+
$$ + T_{iter} = \underbrace{b_{core} \cdot n_K \cdot (T_{load} + T_{cmd})}_{\text{搬移(逐 batch)}} + \underbrace{T_{comp} + T_{write}}_{\text{末 batch drain}} + $$
+
$$ + T_{mb} = \underbrace{\frac{b_{core}}{b_0} \cdot n_K^m \cdot (T_{load}^m + T_{cmd})}_{\text{搬移(合并)}} + \underbrace{b_0(T_{comp} + T_{write})}_{\text{末合并 batch drain}} + $$
+

K 截断情形($k_{L1} = K$,整个 K 装入 L1 一块):$n_K = n_K^m = 1$,$T_{load}^m = b_0 \cdot T_{load}$(合并后数据量 $b_0$ 倍)。

+
$$ + T_{iter} = b_{core}(T_{load} + T_{cmd}) + T_{comp} + T_{write} + $$
+
$$ + T_{mb} = \frac{b_{core}}{b_0}(b_0 T_{load} + T_{cmd}) + b_0(T_{comp} + T_{write}) = b_{core} T_{load} + \frac{b_{core}}{b_0}T_{cmd} + b_0(T_{comp} + T_{write}) + $$
+
$$ + \Delta = T_{mb} - T_{iter} = \underbrace{(b_0-1)(T_{comp} + T_{write})}_{\text{drain 惩罚}} - \underbrace{b_{core}\Big(1-\frac{1}{b_0}\Big) T_{cmd}}_{\text{搬移命令节省}} + $$
+

分界条件(MergeBatch 优于 IterBatch 当且仅当 $\Delta < 0$):

+
$$ + b_{core} > \frac{b_0 \cdot (T_{comp} + T_{write})}{T_{cmd}} + $$
+

小 MN 时 $T_{comp}$ 小 → 惩罚小 → MergeBatch 更容易赢;大 B 时 $b_{core}$ 大 → 搬移节省多 → MergeBatch 更容易赢。

+

**$T_{cmd}$ 的物理成因**:每次 GM→L1 DMA 搬移的固定开销,与搬移数据量无关。从源码可直接观察:

+ +

IterBatch 每 batch 需一次完整配置(ndNum = curIterBatchL1,多块独立寻址);MergeBatch 合并后只需一次配置(ndNum = 1,单块连续搬移)。**$T_{cmd}$ 就是每次 DMA 命令的描述符配置 + 启动延迟**,量级估计为数十 ns。

+

MergeBatch vs IterBatch 优势总结

+ + + + +
维度IterBatchMergeBatch差异来源
稳态搬移吞吐相同相同总搬移量相同
GM→L1 搬移命令数$b_{core}$ 次(每 batch 一次)$b_{core}/b_0$ 次(每合并 batch 一次)**MergeBatch 少 $b_0$ 倍** ← 核心优势
drain 暴露$T_{comp} + T_{write}$$b_0(T_{comp} + T_{write})$IterBatch 少 $b_0$ 倍 ← 核心劣势
L0C 利用率$MN \cdot 4\text{B}$$b_0^2 MN \cdot 4\text{B}$访存 Bound 下不影响时延
+

净收益 = 搬移节省 - drain 惩罚 = $b_{core}(1-\frac{1}{b_0})T_{cmd} - (b_0-1)(T_{comp}+T_{write})$。大 B($b_{core}$ 大)且小 MN($T_{comp}$ 小)时 MergeBatch 最优。

+

L0C 利用率说明:小 MN 时 IterBatch 的 L0C tile($MN \cdot 4\text{B}$)远小于 L0C 容量,MergeBatch 合并后更接近满载。但访存 Bound 下计算被搬移掩盖,L0C 利用率不影响总时延——不构成 MergeBatch 的优势

+
    +
  1. L0C 容量:合并 $b_0$ 个 batch 的输出块 $[b_0M, b_0N]$(FP32 累加、双缓冲两份)必须放得下 L0C;连最小合并都放不下,合并无从谈起。
  2. +
  3. 单核搬移总量:单核搬移数据总量低于 min_DatamountPerCore 时,GM 带宽利用率上不去(重要性第 2 位的经验约束)。
  4. +
  5. 搬移 tile 大小:单 batch 单矩阵的最大连续搬移块须达到 min_TileSize;合并是在此之上进一步放大,不是替代。
  6. +
  7. 访存 Bound:合并把单次计算的算存比放大 $b_0$ 倍后仍须低于 16bit 对应位宽算存比 $R_{16}$,保证瓶颈留在搬移侧,冗余算力被掩盖而非成为新瓶颈。
  8. +
+

实现方案

+

Step 1:合并数 b(L0C + 算存比双上限)

+
$$ +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 2:L0 级 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 3:L1 级 $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}$ 是 GM→L1 的 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. +
  3. $B \bmod C = 0 \;\lor\; B \bmod C \ge minCoreNum$
  4. +
  5. L1 容量约束,四选一(Step 为 >1 的整数):
  6. + +
  7. c/d 切分后:搬移分块 $\ge min\_TileSize \;\land\; dValue \ge 128\text{B}$
  8. +
+

逐条解释

+
    +
  1. batch 关系与每核份额:无广播;每核至少 1 个 batch。
  2. +
  3. 负载均衡:切 B 核间零共享零依赖,唯一系统性风险是负载不均。整除时完全均衡;不整除时尾波活跃核数须 ≥ minCoreNum,保证尾波仍有足够核并发搬移(重要性第 1 位的约束是核数)。
  4. +
  5. L1 容量——核心要求:单 batch 计算不重复读
  6. +
+

重复读发生在单 batch 内部:L1 放不下单 batch 完整的 M、N 维输入(K 维允许切段放入,kL1<K)时,核内切 M 会在 K 循环中重复读 B、切 N 会重复读 A。IterBatch 进入与否不由算存比判定——即使 case 是计算 Bound,重复读引入的额外搬移也可能把它重新拖回访存 Bound。所以进入条件直接由 L1 驻留形态刻画:

+ +
    +
  1. 搬移效率下限:切分把粒度切小,必须守住 min_TileSize 与 dValue,否则切分本身把带宽打崩。
  2. +
+

batch 间流水掩盖分析(c/d 的分工)

+

先明确流水结构:fixpipe 开 unitflag 后,写出由硬件随路完成(每个 16×16×16 fractal 算完即自动搬出),写出侧不需要软件排流水;要掩盖的只有"读入(MTE2: GM→L1)↔ 计算(Cube)"。

+ +

结论:(c) 统一了原 (c)/(d)——同一族"一侧驻留 + 对侧切 K",预算按 $b_{core}$ 分档($b_{core}=1$ 全量 L1、$b_{core} \ge 2$ 减半以容纳下一 batch 驻留侧预取);驻留侧超 L1/2 时由 (d) 接管。

+

实现方案

+

(a):每核 1 batch 直接搬入 L1。L1→L0 先看 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 乒乓,核内 GM→L1→L0→Cube→L0C→GM/L2 流水;L1→L0 分块同理,但各级预算减半(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/2),batch 边界由硬件 fixpipe 自动排空、下一 batch 立即在另一半 L0C 累加。

+
+

七、StreamK 分支

+

进入分支条件(汇总)

+
    +
  1. $P = \dfrac{B \cdot MN \cdot 4\text{B}}{L0C} \le \dfrac{C}{2}$
  2. +
  3. $\dfrac{K}{grid_K} \ge \dfrac{256\text{B}}{\text{dtype}}$,其中 $grid_K = \Big\lfloor \dfrac{C}{\lceil P \rceil} \Big\rfloor$
  4. +
  5. $K > \dfrac{grid_K^{\,2}}{grid_K-1}\cdot\theta_c$,$\theta_c = \dfrac{Q_{16}}{2}\Big(\dfrac{8\text{B}}{W_{L2}}+\dfrac{1}{Q_{AIV}}\Big) \approx 12$
  6. +
  7. 工程约束:确定性等级 ≤ 1(核间归约顺序不定);ND 格式
  8. +
+

逐条解释

+
    +
  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_K;grid_K=2 时每块需要 2 个核,总核数需求 = ⌈P⌉ × 2 ≤ C,即 P ≤ C/2(等号成立时 grid_K=2 恰好填满 C 核)。若 P > C/2,切 2 路就超核数(2⌈P⌉ > C),不切又浪费核——由降核 ASW_Basic 承接更合适。P ≤ C/2 意味着不切 K 时至多一半核有事做,K 是唯一剩余的并行维度。
  2. +
  3. 单核 K 段下限:每核 K 段内轴连续长度不小于 dValue 推荐值 256B(BF16 为 128 元素),保证段内搬移效率不崩。
  4. +
+

grid_K 取值:P 个输出 tile 各需 grid_K 个核,总核数 ⌈P⌉ × grid_K ≤ C → grid_K = ⌊C/⌈P⌉⌋(最大化 K 并行度)。例:P=10, C=32 → grid_K=⌊32/10⌋=3;P=5, C=32 → grid_K=⌊32/5⌋=6;P=16, C=32 → grid_K=⌊32/16⌋=2。

+
    +
  1. 归约代价可接受。StreamK 切 K 引入归约串行尾,收益判据——切 K 后芯片级总时延须小于不切 K(降核 ASW)。
  2. +
+

降核 ASW 的芯片级→核级映射:P < C/2 时 B×M×N 填不满 C 核,以 L0C 满载粒度切为 P 个输出 tile(每 tile 尺寸 $M^t N^t = L0C/4\text{B}$),$\lceil P \rceil$ 个核各处理一个 tile。芯片级总时延 $T_{alt}$ = 单 tile 流水时延 $T_{pipe}$(所有核并行)。$T_{pipe} = \max(T_{MMAD}^t,\,T_{MTE2}^t)$,其中:

+
$$ + T_{MMAD}^t = \frac{2 M^t N^t K}{Q_{16}} = \frac{2K}{Q_{16}}\cdot\frac{L0C}{4\text{B}},\qquad + T_{MTE2}^t = \frac{K(M^t+N^t)\cdot\text{dtype}}{BW_{pc}} + $$
+

StreamK 的芯片级→核级映射:同样 P 个 tile,每 tile 由 $grid_K$ 个核共同完成(各算 $K/grid_K$ 段)。流水时延 $T_{pipe}/grid_K$,归约时延 $T_{Reduce}^t$ 串行追加。芯片级总时延:

+
$$ + T_{SK} = \frac{T_{pipe}}{grid_K} + T_{Reduce}^t + $$
+

收益判据 $T_{SK} < T_{alt}$ ⟺ $T_{Reduce}^t < T_{pipe}\left(1-\dfrac{1}{grid_K}\right)$。等价于 $T_{pipe} > \dfrac{grid_K}{grid_K-1}\cdot T_{Reduce}^t$——α = grid_K/(grid_K-1) 由流水分析导出(grid_K=2 时 α=2),非经验值。

+

**$T_{Reduce}^t$ 构成**(每 tile,部分和驻留 L2、AIV 归约;$M^t N^t = L0C/4\text{B}$,符号定义见 §二):

+
$$ + T_{Reduce}^t = \underbrace{\frac{grid_K \cdot M^t N^t \cdot 4\text{B}}{W_{L2}}}_{\text{AIC 写部分和}} + \underbrace{\frac{grid_K \cdot M^t N^t \cdot 4\text{B}}{W_{L2}}}_{\text{AIV 读回}} + \underbrace{\frac{grid_K \cdot M^t N^t}{Q_{AIV}}}_{\text{AIV 求和}} + \underbrace{\frac{M^t N^t \cdot outB}{W_{L2}}}_{\text{写回}} + $$
+

K 闭式阈值推导——分两种瓶颈情形:

+

计算 Bound($T_{pipe} = T_{MMAD}^t$),代入判据:

+
$$ + \frac{2K}{Q_{16}}\cdot\frac{L0C}{4\text{B}}\cdot\frac{grid_K-1}{grid_K} > grid_K\cdot\frac{L0C}{4\text{B}}\Big(\frac{8\text{B}}{W_{L2}}+\frac{1}{Q_{AIV}}\Big) + \frac{L0C}{4\text{B}}\cdot\frac{outB}{W_{L2}} + $$
+

两边除以 $L0C/4\text{B}$(tile 输出元素数),tile 尺寸消去——K 阈值不依赖 M、N 的具体值:

+
$$ + K > \frac{grid_K^2}{grid_K-1}\cdot\theta_c,\qquad + \theta_c = \frac{Q_{16}}{2}\Big(\frac{8\text{B}}{W_{L2}}+\frac{1}{Q_{AIV}}\Big) + $$
+

代入数值($Q_{16}$=15.2 TFLOPS,$W_{L2}$=5.2 TB/s,$Q_{AIV}$≈13.5 Tops/s):

+
$$ + \theta_c = \frac{15.2\times10^{12}}{2}\Big(\underbrace{\frac{8}{5.2\times10^{12}}}_{1.54\,\text{ps/元素}} + \underbrace{\frac{1}{13.5\times10^{12}}}_{0.07\,\text{ps/元素}}\Big) = 7.6\times10^{12} \times 1.61\times10^{-12} \approx 12 + $$
+

L2 读写(1.54 ps/元素)是主导项,AIV 求和(0.07)仅占 5%。grid_K=2→K>49;4→K>66;8→K>112。

+

访存 Bound($T_{pipe} = T_{MTE2}^t$),同理($M^t N^t/(M^t+N^t)$ 不消去,但阈值远低于计算 Bound):

+
$$ + K > \frac{grid_K^2}{grid_K-1}\cdot\frac{M^t N^t}{M^t+N^t}\cdot\theta_m,\qquad + \theta_m = \frac{BW_{pc}}{\text{dtype}}\Big(\frac{8\text{B}}{W_{L2}}+\frac{1}{Q_{AIV}}\Big) \approx 0.04 + $$
+

访存 Bound 阈值远低于计算 Bound——两情形阈值比值:

+
$$ + \frac{\theta_m \cdot M^t N^t/(M^t+N^t)}{\theta_c} = \frac{2\cdot BW_{pc}}{Q_{16}\cdot\text{dtype}}\cdot\frac{M^t N^t}{M^t+N^t} = \frac{M^t N^t/(M^t+N^t)}{304} + $$
+

$M^t N^t/(M^t+N^t)$ 的范围:tile 面积 $M^t N^t \le L0C/4\text{B} = 65536$ 元素(L0C 容量上限)。由均值不等式 $M^t+N^t \ge 2\sqrt{M^t N^t}$,比值上界为 $\sqrt{M^t N^t}/2 \le \sqrt{65536}/2 = 128$(正方形 tile 取到);极端长宽比($M^t{=}16, N^t{=}4096$)时下界 $\approx 16$。StreamK case 的 tile 通常接近正方形 → 比值 $\sim$ O(64–128),上界 128。无论取何值,$128/304 \approx 0.42 < 1$——访存 Bound 阈值恒低于计算 Bound。直觉:访存 Bound 时 $T_{pipe} = T_{MTE2}^t > T_{MMAD}^t$,瓶颈时延更大,归约预算更充裕。汇总条件取计算 Bound 阈值(保守,同时覆盖两种情形)。

+

注意 θ_c 对 workspace 落点敏感:部分和落 GM 时读写带宽从 5.2TB/s 降到 ~0.64TB/s,θ_c 升至约 97。设计时应优先保证 workspace 驻留 L2。

+
    +
  1. 工程约束:归约顺序不定引入浮点非确定性,确定性等级 2/3 的业务禁用。
  2. +
+

源码对照batch_matmul_v3_basic_streamk_tiling.cpp 中 K 的固定门槛为 CeilAlign(K,256) ≥ max(8192, aicNum×256B/dtype)

+ +

max 取更严格的 8192。修正后的归约阈值(θ_c≈12,grid_K=32 时 K>396)远低于 8192,说明 8192 的绑定约束是 dValue(条件 2),不是归约代价(条件 3)。源码不动态计算 grid_K,用固定阈值同时覆盖条件 2 的最保守情形和条件 3,是两条条件的保守合并近似。

+

实现方案

+

Step 0:SingleCoreM / SingleCoreN 的确定(每核输出 tile 尺寸)

+

SingleCoreM × SingleCoreN 是每核每次处理的输出区域。它不受 L0 容量直接约束——L0 容量约束的是 BaseM/BaseN/BaseK(L0 级 tile,见 Step 5),SingleCoreM/N 在 BaseM/N 之上,一个 [SingleCoreM, SingleCoreN] tile 内部由多个 [BaseM, BaseN] L0 tile 组成。SingleCoreM/N 的核心影响是 GM→L1 搬移效率和 L2 重复读率

+ +

*约束链*:

+

约束 1——并行度下限:总块数须填满 C 核。

+
$$ +mCnt \times nCnt \ge \Big\lceil \frac{C}{B} \Big\rceil \Rightarrow \frac{M}{\text{singleCoreM}} \times \frac{N}{\text{singleCoreN}} \ge \Big\lceil \frac{C}{B} \Big\rceil +$$
+

约束 2——L1 容量(双缓冲下驻留当前 tile 的输入):

+
$$ +2 \cdot (\text{singleCoreM} + \text{singleCoreN}) \cdot k_{L1} \cdot \text{dtype} \le L1 +$$
+

其中 $k_{L1}$ 是 GM→L1 的 K 向粒度,须满足 dValue:$k_{L1} \cdot \text{dtype} \ge 256\text{B}$。

+

约束 3——搬移效率:单次 GM→L1 搬移量须达到 min_TileSize:

+
$$ +\text{singleCoreM} \cdot k_{L1} \cdot \text{dtype} \ge min\_TileSize,\qquad k_{L1} \cdot \text{singleCoreN} \cdot \text{dtype} \ge min\_TileSize +$$
+

选取策略

+

在约束 1(并行度下限)和约束 2/3(搬移效率)之间取平衡。SingleCoreM/N 的长宽比应跟随 M/N 的长宽比($\text{singleCoreM}/\text{singleCoreN} \approx M/N$),使 GM 访问的空间局部性最优。对齐到 16 的倍数(Cube 基本块粒度)。

+

*例*(B=8、M=N=2048、K=1024、BF16):$\lceil C/B \rceil = 4$,需 $mCnt \times nCnt \ge 4$。取 $mCnt = nCnt = 2$ → singleCoreM = singleCoreN = 1024。约束 2:$k_{L1} \le 512\text{KB}/(2 \times 2048 \times 2\text{B}) = 64$ 元素 = 128B,恰好满足 dValue 下限。约束 3:$1024 \times 64 \times 2 = 128\text{KB} \ge 16\text{KB}$ ✓。

+

*例*(B=2、M=N=4096、K=512、BF16):$\lceil C/B \rceil = 16$,需 $mCnt \times nCnt \ge 16$。取 $mCnt = nCnt = 4$ → singleCoreM = singleCoreN = 1024。$k_{L1}$ 同上 = 64 元素。

+

Step 1:mCnt / nCnt 与核间分配

+
$$ +mCnt = \Big\lceil \frac{M}{\text{singleCoreM}} \Big\rceil,\qquad nCnt = \Big\lceil \frac{N}{\text{singleCoreN}} \Big\rceil +$$
+

总输出块数 = $B \times mCnt \times nCnt$,按 B→M→N 优先级分配到 C 核。

+

Step 2:核间切分维度选择(按共享代价从低到高):切 B(零共享,先试)→ 切 M(右矩阵 $KN\cdot\text{dtype} \le L2$ 则驻留 L2)→ 切 N(对称)→ 混合切(靠 swizzle + L2 切分管理)→ 降核(见 Step 7)。

+

Step 3:swizzle——ASW 滑窗蛇形

+

问题:核间切 M/N 后,同一时刻 C 个核各算一个输出块,它们所需的 A 行块与 B 列块集合就是当前"活跃工作集"。若按行优先顺序朴素分配,一波 C 个块横跨的 A 行、B 列很宽,活跃工作集超过 L2 就回 GM 读(1.6TB/s),重复读代价真实发生。swizzle 要做的就是编排输出块的执行顺序,把每一波核的活跃工作集压到最小。

+

做法:把 M 向每 W 个基本块划为一个"窗口",遍历顺序为"窗口内先扫 M、扫满 W 行再进下一列 N;一个窗口扫完再进下一个窗口",且奇数窗口行 N 向反向(蛇形)。效果有二:

+ +

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=32,W=4,M̃=8,Ñ=8;数字为块的全局执行顺序,一波 32 块):

+
窗口0(N 正向)                窗口1(N 蛇形反向)
+      ν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^t)·K·dtype;滑窗为 (4·M^t + 8·N^t)·K·dtype——M^t≈N^t 时足迹缩小 1/3。

+

窗内为什么不蛇形(对上例中"块 3=(μ3,ν0) → 块 4=(μ0,ν1) 而非 (μ3,ν1)"的说明):蛇形的收益来自"相邻遍历段共享边界数据",要分两种边界看:

+ +

Step 4:L2 分组(工作集超 L2 时)

+

切的是什么:将 mCnt×nCnt 个基本块划分为若干执行组——每组覆盖输出平面上一个连续矩形区域(若干 singleCoreM × singleCoreN 基本块的集合),使该组所需的 A 行带 + B 列带输入工作集 ≤ L2 可用读入空间;组内所有基本块算完再进下一组,输入只在跨组时换一次。

+

为什么需要它:滑窗压缩的只是"同一波"的足迹;若整个工作集超 128MB L2,跨波次复用落空——上一波窗口的 A 行早被挤出,下一波又得回 GM 读。且 L2 是读写共用的:输出经 fixpipe 写出时若驻留 L2(dirty),会压缩读入可用空间;若直写 GM,则占用与读共享的 1.6TB/s 总线。所以 L2 切分必须与写出策略联合决策。记输入总量 $S_{in} = B(MK+KN)\cdot\text{dtype}$,输出总量 $S_{out} = B \cdot MN \cdot outB$。

+

两个不变量(一切分析的起点):

+ +

重复读倍率:$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} +$$
+

只与 K、outB 有关(K 越小,单位时间输出越密)。例(BF16 输出,C·Q₁₆=432 TFLOPS):K=512 → 844 GB/s;K=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$),输出驻留 L2(dirty)异步回写 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. +
  3. 输出在本算子内只写不读、零复用收益;若输出也驻留 L2(dirty),超出 L2 的部分会把输入挤出——被挤出的输入后续得回 GM 重读 ⇒ $r_{in} > 1$,GM 流量超出下界;
  4. +
  5. 故让输出直写 GM(fixpipe L0C→GM,不占 L2),把 128MB 全部留给输入,保住 $r_{in} = 1$——GM 总流量保持下界 $S_{in} + S_{out}$;
  6. +
  7. 代价是输出即刻占用 GM 写带宽(与读共享总线),须校验总线不爆:$(S_{in} + S_{out})/T_{MMAD} \le W_{GM}$。
  8. +
+

例:B=8、M=N=4096、K=512、BF16——$S_{in}$≈67MB ≤ L2,$S_{out}$≈268MB 直写 GM;T_MMAD≈318µs,总流量速率 (67+268)MB/318µs ≈ 1.05TB/s < 1.6TB/s ✓。

+

**场景 C:$S_{in} > L2$(输入本身超)。需要分组执行——把 mCnt×nCnt 个基本块划分为若干执行组**,每组内所有基本块的输入工作集不超过 L2 可用空间。输出直写 GM(不占 L2 读入空间)。

+

L2 的软件可控手段:L2 是 Cache 而非 Buffer,软件无法精确控制"哪些数据在 L2 里"。可用的控制手段:

+ +

执行组的划分

+

*问题*:mCnt×nCnt 个基本块(每块输出 singleCoreM×singleCoreN),按什么粒度分组,使每组的输入工作集 ≤ L2?

+

*每组输入工作集*:一组覆盖 M 向 $m_{grp}$ 个基本块、N 向 $n_{grp}$ 个基本块,即覆盖输出区域 $[m_{grp} \cdot \text{singleCoreM},\; n_{grp} \cdot \text{singleCoreN}]$。该区域需要读入的输入:

+
$$ +WS_{grp} = B \cdot K \cdot \big(m_{grp} \cdot \text{singleCoreM} + n_{grp} \cdot \text{singleCoreN}\big) \cdot \text{dtype} \;\le\; L2 +$$
+

*目标*:最小化组数(组数越少,输入从 GM 的重复读次数越少)。每行 A 被 $n_{grp}$ 个组各读一次,每列 B 被 $m_{grp}$ 个组各读一次:

+
$$ +r_{in} = \frac{n_{grp} \cdot M + m_{grp} \cdot N}{M + N} +$$
+

*求解*:约束 $m_{grp} \cdot \text{singleCoreM} + n_{grp} \cdot \text{singleCoreN} \le D$(其中 $D = L2/(B \cdot K \cdot \text{dtype})$),最小化 $n_{grp} \cdot M + m_{grp} \cdot N$。最优在组内 M/N 向基本块数与输出平面形状成正比时取到:

+
$$ +m_{grp} = \Big\lfloor \frac{D}{2 \cdot \text{singleCoreM}} \Big\rfloor,\qquad n_{grp} = \Big\lfloor \frac{D}{2 \cdot \text{singleCoreN}} \Big\rfloor +$$
+

总组数 $= \lceil mCnt/m_{grp} \rceil \times \lceil nCnt/n_{grp} \rceil$。

+

组内 swizzle:每组内部按 ASW 滑窗蛇形执行(窗口 $W = \max\{d \mid d \mid C,\; d \le \lfloor\sqrt{C}\rfloor\}$,C=32 时 W=4),保证同一波 C 个核的活跃工作集最小。组间切换时输入整体换入——上一组的 A 行带和 B 列带全部失效,从 GM 重新读入下一组的数据。

+

*例*(B=64、M=N=2048、K=1024、BF16、singleCoreM=singleCoreN=256):$S_{in} = 64 \times (2048 \times 1024 + 1024 \times 2048) \times 2 = 537\text{MB} > 128\text{MB}$。$D = 128\text{MB}/(64 \times 1024 \times 2\text{B}) = 1024$ 元素。$m_{grp} = \lfloor 1024/(2 \times 256) \rfloor = 2$,$n_{grp} = 2$。每组覆盖 $[512, 512]$ 的输出区域,工作集 $= 64 \times 1024 \times (512+512) \times 2 = 128\text{MB} = L2$,恰好装满。总组数 $= (2048/256/2)^2 = 16$。$r_{in} = (2 \times 2048 + 2 \times 2048)/(2048+2048) = 2$——每行 A 被读 2 次,每列 B 被读 2 次。

+

块内分配用错位分核(对角线分配):线性块号先取 m,n 方向叠加随块号递增的相位偏移,使同一时刻各核落在 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 的方向。

+

补充:若输出会被后续算子立即消费(融合场景),输出驻留 L2 让下游读命中,场景 B/C 的策略反过来;本文按单算子边界分析。

+

Step 5:核内 tiling(BaseM/BaseN/BaseK——L0 级 tile,受 L0 容量直接约束):$\text{BaseM} \times \text{BaseN} \times 4\text{B} \times DB \le L0C$;$\text{BaseM} \times k_{L0} \times \text{dtype} \times 2 \le L0A$、$k_{L0} \times \text{BaseN} \times \text{dtype} \times 2 \le L0B$;内轴按 dValue 256B/512B 对齐。SingleCoreM/N 内部按 BaseM/BaseN 进一步切分为 L0 tile 逐个计算。L1 按容量开双缓冲,余量充足开 4 buffer。

+

Step 6:内部特化(参数极限,不是独立分支):单边无 batch 且该侧矩阵小($M \le 256$、$MK\cdot\text{dtype}\cdot 2 \le L1$、对侧每核循环 ≥4 轮)时小侧整个常驻 L1、只搬一次(L1 全载)。

+

Step 7:降核模式实现:tiling 时 usedCoreNum = ⌈P⌉(不强制 C),SingleCoreM/N 在 L0C 容量内取最大($\text{singleCoreM} \times \text{singleCoreN} \times 4\text{B} \le L0C$),每核按标准核内流水(L1→L0→Cube→L0C→Fixpipe)处理自己的输出块;核间无共享无依赖,无需 swizzle 与 L2 切分。降核后 GM 并发搬移核数若 < minCoreNum,带宽利用率上限被压低——这正是降核区 case 时延的瓶颈所在,也是"时延绝对值小、不再继续优化"的定量注脚。

+
+

九、特殊分支

+ +
+

十、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¹⁵ 个 case。Python 分类器约需 1400 万小时,C 实现约需 6 万小时——完全不可行。对数采样在小值区密集、大值区稀疏,恰好覆盖了分支边界集中的区域。

+

分布依赖测度:对数均匀采样和线性均匀采样给出的分支占比不同。对数采样在小值区密集,特殊分支(K=0/1)、降核 ASW(P 小)、StreamK(K 大但 M/N 小)的占比被放大;线性采样被大 shape 主导(M/N/K > 512 占 [1,10240] 的 95%+),ASW_Basic 占比显著升高。本文遍历的目的是验证覆盖性(无空洞),不是统计真实工作负载的分布。

+

分支覆盖统计(对数采样,B 全量 2048,M/N/K 60 点/维,共 3.2 亿 case)

+ + + + + + + +
分支case 数占比B 范围区域特征
ASW_Basic1.75 亿54.1%2 ~ 2048通用:B<C 且 P≥C;或 B≥C 但 L1 四形态不满足(M/N 大)
MergeBatch6303 万19.5%97 ~ 2048$b_{core}\ge 4$ 且 $MN \le 8192$ 等五条全过
降核 ASW_Basic4051 万12.6%2 ~ 2048P<C 且 K 不满足 StreamK 阈值 → 只用 ⌈P⌉ 核
IterBatch3804 万11.8%32 ~ 2048B≥C、负载均衡、L1 四形态之一满足
特殊分支597 万1.9%任意K=0 / K=1
StreamK25 万0.08%2 ~ 128P<C/2 且 K≥8192
转Matmul15 万0.05%B=1单边 batch=1
+

对照:线性等距采样(M/N/K 步长 256,B 全量,共 1.3 亿 case)下 ASW_Basic 占比升至 92.1%,MergeBatch 降至 3.6%——因为线性采样被大 shape 主导。两种测度的结论一致:无空分支、无覆盖空洞,只是占比不同。

+

IterBatch 四形态命中分布(对数采样)

+ + + + +
形态命中数占比说明
b) 双 batch 乒乓2684 万70.5%最多:B 大且单 batch 较小
d) 两侧切 K741 万19.5%次之:K 可切段的通用兜底
c) 一侧驻留+对侧切 K370 万9.7%单侧可驻留(含 b_core≥2 的半预算预取档)
a) 单 batch 全驻留9 万0.2%B=C 附近的窄区
+

典型边界 case

+ + + + + + + + + + + +
BMNK分支说明
1204820482048转Matmul单 batch 纯 Matmul
1286464512MergeBatch五条全过:$b_{core}$=4,MN=4096≤8192,单核搬移 512KB≥480KB,AI=64<304
1286464256IterBatch与上行仅 K 不同:单核搬移 256KB < 480KB,条件 3 不满足 → 落 IterBatch(形态 b)
512128128128IterBatchMN=16384 > 8192,MergeBatch 条件 2 不满足 → 落 IterBatch
32409640964096ASW_BasicL1 四形态均不满足(M/N 太大),切 M/N
2819281921024ASW_BasicB<C,P=2048 ≥ 32
16256256128降核 ASWP=4 < 32 且 K=128 不满足 StreamK → 用 4 核,其余闲置
412812810240StreamKP=0.25 < 32,K≥8192
204810241024512IterBatch大 batch,形态 b
8512512512ASW_BasicB<C,P=32 恰好满核
6464648192IterBatch小 M×N 但 K 大,形态 d
+

遍历结论

+
    +
  1. 七个分支全部有真实 case 命中,无空分支;覆盖矩阵无空洞(P<C 且 K 小的残余由降核 ASW_Basic 兜底——此时时延绝对值小,调度开销主导,分支选择不敏感);
  2. +
  3. **MergeBatch 的区域由条件 2($MN \le 8192$)与条件 3(min_DatamountPerCore)夹出**:小 M×N 且单核搬移量足够的大 batch case,两个条件缺一不可。典型分界对照:B=128/M=N=64 时 K=256 → 单核搬移 256KB 不达标落 IterBatch,K=512 → 512KB 达标进 MergeBatch;
  4. +
  5. IterBatch 与 ASW_Basic 的分界就是 L1 四形态是否满足:单 batch 输入 $(MK+KN)\cdot\text{dtype}$ 相对 L1 的比例决定归属——这正是"核内零重复读"原则的定量体现;
  6. +
  7. StreamK 的区域为 P<C/2 且 K≥8192:B 小、M/N 小、K 大的"细长" case;C/2 ≤ P < C 且 K 大的 case 由降核 ASW_Basic 承接(切 2 路 K 会超核数,不切又不满核,不如直接用 ⌈P⌉ 核);
  8. +
  9. 降核 ASW_Basic 是 P<C 且 K 小区域的理性归宿(占 12.6%):并行度凑不满、切 K 又不划算时,只用 ⌈P⌉ 个核、每核一个 L0C 满载输出块,比强行碎切(tile 跌破搬移效率下限)更快。
  10. +
+
+ + \ No newline at end of file