diff --git a/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html b/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html index 06adc05..1d32b5c 100644 --- a/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html +++ b/BMM算子优化分析_Release/BMM算子优化分析_v0.94.html @@ -344,58 +344,35 @@ $$
max 取更严格的 8192。修正后的归约阈值(θ_c≈12,grid_K=32 时 K>396)远低于 8192,说明 8192 的绑定约束是 dValue(条件 2),不是归约代价(条件 3)。源码不动态计算 grid_K,用固定阈值同时覆盖条件 2 的最保守情形和条件 3,是两条条件的保守合并近似。
Step 0:singleCoreM / singleCoreN 的确定(每核输出基本块尺寸)
-singleCoreM × singleCoreN 是 ASW_Basic 的基石参数——它决定了每核每次计算的输出 tile 大小,进而决定 mCnt/nCnt、swizzle 窗口、L2 执行组等所有后续参数。确定逻辑按约束链推导:
-*约束 1——L0C 容量*(输出 tile 必须放得下 L0C 双缓冲):
+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 核。
*约束 2——L0A/L0B 容量*(输入 tile 决定 baseK 上限):
-*约束 3——dValue*:$baseK \cdot \text{dtype} \ge 256\text{B}$(BF16 为 128 元素)。
-*约束 4——L1 容量*(双缓冲下驻留输入):
+约束 2——L1 容量(双缓冲下驻留当前 tile 的输入):
*约束 5——搬移效率*:$\text{singleCoreM} \cdot K \cdot \text{dtype} \ge min\_TileSize$ 且 $K \cdot \text{singleCoreN} \cdot \text{dtype} \ge min\_TileSize$。
-*选取策略*:在约束 1 的上界(32768 元素)内,singleCoreM/singleCoreN 的长宽比应跟随 M/N 的长宽比——$\text{singleCoreM}/\text{singleCoreN} \approx M/N$,使 GM 访问的空间局部性最优(减少跨行/跨列的 strided 访问)。同时对齐到 16 的倍数(Cube 基本块粒度)。
-*例*:M=N=2048,方形 → singleCoreM=singleCoreN=$\lfloor\sqrt{32768}\rfloor_{16}$=176。约束 2:$baseK \le 16384/176 = 93$ → 取 80(16 对齐)。约束 3:$80 \times 2 = 160\text{B} \ge 128\text{B}$ ✓。
-*例*:M=4096、N=512,长条 → singleCoreM=256、singleCoreN=128($256 \times 128 = 32768$ 恰好满载 L0C/2)。约束 2:$baseK \le \min(16384/256, 16384/128) = \min(64, 128) = 64$。
+其中 $k_{L1}$ 是 GM→L1 的 K 向粒度,须满足 dValue:$k_{L1} \cdot \text{dtype} \ge 256\text{B}$。
+约束 3——搬移效率:单次 GM→L1 搬移量须达到 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 与核间分配
总输出块数 = $B \times mCnt \times nCnt$,按 B→M→N 优先级分配到 C 核。
-核间组织:先按 B/M/N 切出输出块,剩余核预算折成 K 向份数:
-mCnt、nCnt 收拢为 blocksPerBatch 的因子(避免碎核尾块);由条件 1 知 $mCnt \cdot nCnt \le blocksPerBatch/2$,故 $grid_K \ge 2$。归约组内核 c 负责 K 段 $[cK/grid_K,\; (c{+}1)K/grid_K)$。
-核内流水:对自己的 K 段做标准分块流水(MTE2→L1→L0→mmad),段内多轮在 L0C 原地累加;段完部分和经 Fixpipe 写出。
-归约:
-参数搜索:$grid_K$ 从 2 起按 2 的幂递增,取同时满足条件 2/3 的最小值;都不满足则退为降核 ASW_Basic。
-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 要做的就是编排输出块的执行顺序,把每一波核的活跃工作集压到最小。
@@ -490,9 +467,9 @@ transConflict = \max\big(\lceil C / mCnt \rceil,\; \lceil C / nCnt \rceil\big) \ $$即同一时刻并发核访问同一 A/B 块的最大冲突数不超过阈值(经验值 6);切分方案中优先选尾波不满载占比小(拖尾 < 一半)的。遍历大方向由 calOrder 决定(0=M 优先、1=N 优先),按形状选共享矩阵更能驻留 L2 的方向。
补充:若输出会被后续算子立即消费(融合场景),输出驻留 L2 让下游读命中,场景 B/C 的策略反过来;本文按单算子边界分析。
-Step 5:核内 tiling:$\text{singleCoreM} \times \text{singleCoreN} \times 4\text{B} \times DB \le L0C$;$\text{singleCoreM} \times k_{L0} \times \text{dtype} \times 2 \le L0A$、$k_{L0} \times \text{singleCoreN} \times \text{dtype} \times 2 \le L0B$;内轴按 dValue 256B/512B 对齐;L1 按容量开双缓冲,余量充足开 4 buffer。
+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),基本块在 L0C 容量内取最大($M^t N^t \cdot 4\text{B} \le L0C$),每核按标准核内流水(L1→L0→Cube→L0C→Fixpipe)处理自己的输出块;核间无共享无依赖,无需 swizzle 与 L2 切分。降核后 GM 并发搬移核数若 < minCoreNum,带宽利用率上限被压低——这正是降核区 case 时延的瓶颈所在,也是"时延绝对值小、不再继续优化"的定量注脚。
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 时延的瓶颈所在,也是"时延绝对值小、不再继续优化"的定量注脚。