From 7a670e193d82260cec5a959564d783c4885b0999 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 22 Aug 2026 09:45:39 +0000 Subject: [PATCH] =?UTF-8?q?v0.6=20=E4=BF=AE=E8=AE=A2=EF=BC=9AASW=20swizzle?= =?UTF-8?q?=20=E4=B8=8E=20L2=20=E5=88=87=E5=88=86=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E5=8E=9F=E7=90=86=E6=8E=A8=E5=AF=BC=E4=B8=8E=E5=AE=9E=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BMM算子优化分析_v0.6.md | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/BMM算子优化分析_Release/BMM算子优化分析_v0.6.md b/BMM算子优化分析_Release/BMM算子优化分析_v0.6.md index d9b6d99..e5fa22f 100644 --- a/BMM算子优化分析_Release/BMM算子优化分析_v0.6.md +++ b/BMM算子优化分析_Release/BMM算子优化分析_v0.6.md @@ -312,15 +312,53 @@ mCnt、nCnt 收拢为 blocksPerBatch 的因子(避免碎核尾块);由条 **1、核间切分维度选择(按共享代价从低到高)**:切 B(零共享,先试)→ 切 M(右矩阵 $KN\cdot\text{dtype} \le L2$ 则驻留 L2)→ 切 N(对称)→ 混合切(靠 swizzle + L2 切分管理)→ 降核(见第 6 条)。 -**2、swizzle:ASW 滑窗蛇形**。M 向按窗口 W 分组,窗内 N 向蛇形遍历: +**2、swizzle:ASW 滑窗蛇形** + +**问题**:核间切 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 足迹约为 $$ -W = \max\{\,d \mid d \mid C,\; d \le \lfloor\sqrt{C}\rfloor\,\} \quad (C{=}32 \Rightarrow W{=}4) +footprint \approx \big(W \cdot M^t K + \tfrac{C}{W} \cdot K N^t\big) \cdot \text{dtype} $$ -同一时刻 C 个核的活跃工作集被压缩到"W 个 A 行块 + 一条 B 列块带",L2 足迹最小。窗取 $\lfloor\sqrt C\rfloor$ 的最大因子:窗越接近方形两侧足迹之和越小,且因子性保证整窗被核数均分、边界不碎。 +由均值不等式,$W + C/W$ 在 $W = \sqrt{C}$ 处取最小——窗口越接近"方形"(W 行 × C/W 列),足迹越小。同时 W 须整除 C,保证每个窗口恰好被整数波核覆盖、窗口边界不把波次切碎。合起来即: -**3、L2 切分**:工作集超 128MB 时按 mL2TileNum×nL2TileNum 切块,块内错位分核(对角线分配),避免多核同时抢同一地址的读读冲突,优先选拖尾小的方案。 +$$ +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、L2 切分(工作集超 L2 时)** + +**问题**:滑窗压缩的是"同一波"的足迹;若整个工作集(全部 A 行 + 全部 B 列,跨所有窗口)超过 128MB L2,跨波次的复用仍会落空——上一波窗口的 A 行早被挤出 L2,下一波又得回 GM 读。 + +**做法**:把 M×N 平面按 mL2TileNum × nL2TileNum 切成若干"L2 块",每块的工作集控制在 L2 容量内,逐块计算——块内滑窗复用充分,块间才发生一次性换入。块内分配用**错位分核**(对角线分配):线性块号先取 m,n 方向再叠加一个随块号递增的相位偏移,使同一时刻各核落在 M×N 平面的不同对角线上——避免多核同一拍并发读同一行 A / 同一列 B 的同一地址(同地址并发读会串行化,等效带宽打折)。冲突度量取 + +$$ +transConflict = \max\big(\lceil C / mCnt \rceil,\; \lceil C / nCnt \rceil\big) +$$ + +即同一时刻并发核访问同一 A/B 块的最大冲突数,要求不超过阈值(经验值 6);切分方案中优先选尾波不满载占比小(拖尾 < 一半)的。遍历大方向由 calOrder 决定(0=M 优先、1=N 优先),按形状选共享矩阵更能驻留 L2 的方向。 **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。