v0.6 修订:ASW swizzle 与 L2 切分补充原理推导与实例
This commit is contained in:
@@ -277,12 +277,37 @@ $$</div>
|
||||
</ol>
|
||||
<h3>实现方案</h3>
|
||||
<p><b>1、核间切分维度选择(按共享代价从低到高)</b>:切 B(零共享,先试)→ 切 M(右矩阵 $KN\cdot\text{dtype} \le L2$ 则驻留 L2)→ 切 N(对称)→ 混合切(靠 swizzle + L2 切分管理)→ 降核(见第 6 条)。</p>
|
||||
<p><b>2、swizzle:ASW 滑窗蛇形</b>。M 向按窗口 W 分组,窗内 N 向蛇形遍历:</p>
|
||||
<p><b>2、swizzle:ASW 滑窗蛇形</b></p>
|
||||
<p><b>问题</b>:核间切 M/N 后,同一时刻 C 个核各算一个输出块,它们所需的 A 行块与 B 列块集合就是当前"活跃工作集"。若按行优先顺序朴素分配,一波 C 个块横跨的 A 行、B 列很宽,活跃工作集超过 L2 就回 GM 读(1.6TB/s),重复读代价真实发生。<b>swizzle 要做的就是编排输出块的执行顺序,把每一波核的活跃工作集压到最小。</b></p>
|
||||
<p><b>做法</b>:把 M 向每 W 个基本块划为一个"窗口",遍历顺序为"窗口内先扫 M、扫满 W 行再进下一列 N;一个窗口扫完再进下一个窗口",且奇数窗口行 N 向反向(蛇形)。效果有二:</p>
|
||||
<ul class="tight">
|
||||
<li>同一波 C 个核的块集中在同一个窗口内 ⇒ 活跃 A 行块只有 W 个、活跃 B 列块只有 C/W 条带;</li>
|
||||
<li>蛇形反向使相邻窗口行首尾相接——上一窗口末尾的 B 列带与下一窗口开头的 B 列带是同一条,跨窗口切换时工作集增量最小。</li>
|
||||
</ul>
|
||||
<p><b>W 怎么取</b>:一波 C 个块的 L2 足迹约为</p>
|
||||
<div class="math">$$
|
||||
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}
|
||||
$$</div>
|
||||
<p>同一时刻 C 个核的活跃工作集被压缩到"W 个 A 行块 + 一条 B 列块带",L2 足迹最小。窗取 $\lfloor\sqrt C\rfloor$ 的最大因子:窗越接近方形两侧足迹之和越小,且因子性保证整窗被核数均分、边界不碎。</p>
|
||||
<p><b>3、L2 切分</b>:工作集超 128MB 时按 mL2TileNum×nL2TileNum 切块,块内错位分核(对角线分配),避免多核同时抢同一地址的读读冲突,优先选拖尾小的方案。</p>
|
||||
<p>由均值不等式,$W + C/W$ 在 $W = \sqrt{C}$ 处取最小——窗口越接近"方形"(W 行 × C/W 列),足迹越小。同时 W 须整除 C,保证每个窗口恰好被整数波核覆盖、窗口边界不把波次切碎。合起来即:</p>
|
||||
<div class="math">$$
|
||||
W = \max\{\,d \mid d \mid C,\; d \le \lfloor\sqrt{C}\rfloor\,\}
|
||||
$$</div>
|
||||
<p>C=32 时 $\sqrt{32} \approx 5.66$,因子 {1,2,4,8,…} 中不超过它的最大者是 4,故 W=4。</p>
|
||||
<p><b>实例</b>(C=32,W=4,M̃=8,Ñ=8;数字为块的全局执行顺序,一波 32 块):</p>
|
||||
<pre><code>窗口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</code></pre>
|
||||
<p>块 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。</p>
|
||||
<p><b>3、L2 切分(工作集超 L2 时)</b></p>
|
||||
<p><b>问题</b>:滑窗压缩的是"同一波"的足迹;若整个工作集(全部 A 行 + 全部 B 列,跨所有窗口)超过 128MB L2,跨波次的复用仍会落空——上一波窗口的 A 行早被挤出 L2,下一波又得回 GM 读。</p>
|
||||
<p><b>做法</b>:把 M×N 平面按 mL2TileNum × nL2TileNum 切成若干"L2 块",每块的工作集控制在 L2 容量内,逐块计算——块内滑窗复用充分,块间才发生一次性换入。块内分配用<b>错位分核</b>(对角线分配):线性块号先取 m,n 方向再叠加一个随块号递增的相位偏移,使同一时刻各核落在 M×N 平面的不同对角线上——避免多核同一拍并发读同一行 A / 同一列 B 的同一地址(同地址并发读会串行化,等效带宽打折)。冲突度量取</p>
|
||||
<div class="math">$$
|
||||
transConflict = \max\big(\lceil C / mCnt \rceil,\; \lceil C / nCnt \rceil\big)
|
||||
$$</div>
|
||||
<p>即同一时刻并发核访问同一 A/B 块的最大冲突数,要求不超过阈值(经验值 6);切分方案中优先选尾波不满载占比小(拖尾 < 一半)的。遍历大方向由 calOrder 决定(0=M 优先、1=N 优先),按形状选共享矩阵更能驻留 L2 的方向。</p>
|
||||
<p><b>4、核内 tiling</b>:$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。</p>
|
||||
<p><b>5、内部特化(参数极限,不是独立分支)</b>:单边无 batch 且该侧矩阵小($M \le 256$、$MK\cdot\text{dtype}\cdot 2 \le L1$、对侧每核循环 ≥4 轮)时小侧整个常驻 L1、只搬一次(L1 全载)。</p>
|
||||
<p><b>6、降核模式实现</b>:tiling 时 <code>usedCoreNum = ⌈P⌉</code>(不强制 C),基本块在 L0C 容量内取最大($M^t N^t \cdot 4\text{B} \le L0C$),每核按标准核内流水(L1→L0→Cube→L0C→Fixpipe)处理自己的输出块;核间无共享无依赖,无需 swizzle 与 L2 切分。降核后 GM 并发搬移核数若 < minCoreNum,带宽利用率上限被压低——这正是降核区 case 时延的瓶颈所在,也是"时延绝对值小、不再继续优化"的定量注脚。</p>
|
||||
|
||||
Reference in New Issue
Block a user