263 lines
16 KiB
HTML
263 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>BMM算子优化分析 — 讲解PPT</title>
|
||
<style>
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
body{font-family:"PingFang SC","Microsoft YaHei",sans-serif;background:#0f172a;color:#e2e8f0;overflow:hidden}
|
||
.slide{display:none;width:100vw;height:100vh;padding:60px 80px;flex-direction:column;justify-content:center}
|
||
.slide.active{display:flex}
|
||
.slide h1{font-size:42px;color:#38bdf8;margin-bottom:16px}
|
||
.slide h2{font-size:32px;color:#818cf8;margin-bottom:24px}
|
||
.slide h3{font-size:24px;color:#c4b5fd;margin:20px 0 12px}
|
||
.slide p{font-size:20px;line-height:1.7;margin:8px 0}
|
||
.slide ul,.slide ol{font-size:19px;line-height:1.8;margin-left:28px}
|
||
.slide li{margin:6px 0}
|
||
.slide .tag{display:inline-block;background:#1e293b;border:1px solid #334155;border-radius:6px;padding:2px 10px;font-size:16px;margin:3px;color:#94a3b8}
|
||
.slide .eq{font-family:monospace;font-size:18px;color:#fbbf24;background:#1e293b;padding:4px 10px;border-radius:6px}
|
||
.slide table{font-size:17px;border-collapse:collapse;margin:12px 0;width:100%}
|
||
.slide th,.slide td{border:1px solid #334155;padding:8px 14px;text-align:left}
|
||
.slide th{background:#1e293b;color:#818cf8}
|
||
.slide td{background:#0f172a}
|
||
.slide .hl{color:#fbbf24}
|
||
.slide .ct{color:#38bdf8}
|
||
.slide .sub{color:#94a3b8;font-size:16px}
|
||
.slide .note{color:#f87171;font-size:16px;margin-top:16px}
|
||
.nav{position:fixed;bottom:24px;right:32px;display:flex;gap:12px;z-index:100}
|
||
.nav button{background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:8px;padding:10px 20px;font-size:16px;cursor:pointer}
|
||
.nav button:hover{background:#334155}
|
||
.nav .pg{font-size:15px;color:#94a3b8;align-self:center;min-width:60px}
|
||
.code{font-family:monospace;font-size:16px;background:#1e293b;padding:12px 18px;border-radius:8px;margin:10px 0;white-space:pre;line-height:1.5;color:#e2e8f0}
|
||
.dot{color:#38bdf8;font-weight:bold}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="nav">
|
||
<span class="pg" id="pg">1/14</span>
|
||
<button onclick="go(-1)">◀</button>
|
||
<button onclick="go(1)">▶</button>
|
||
</div>
|
||
|
||
<!-- Slide 1: Title -->
|
||
<div class="slide active" id="s1">
|
||
<h1>BMM 算子最优实现分析</h1>
|
||
<p style="font-size:28px;color:#c4b5fd">昇腾 950PR — BatchMatMulV3</p>
|
||
<p class="sub">v0.7|基于 CANN 源码 + 950PR 白皮书 + 架构规格的系统推导</p>
|
||
<p class="sub" style="margin-top:30px">这份分析靠谱吗?→ 最后一页有验证</p>
|
||
</div>
|
||
|
||
<!-- Slide 2: 问题引入 -->
|
||
<div class="slide" id="s2">
|
||
<h2>1. 什么是 BMM 算子?</h2>
|
||
<p>Batch MatMul:对 batch 维的每个索引独立做一次矩阵乘</p>
|
||
<div class="eq">C[b, m, n] = Σₖ A[b, m, k] · B[b, k, n] + bias</div>
|
||
<p style="margin-top:16px">输入:左矩阵 <span class="hl">[BatchA, M, K]</span>、右矩阵 <span class="hl">[BatchB, K, N]</span></p>
|
||
<p>输出:<span class="hl">[BatchC, M, N]</span>,batch 维支持广播</p>
|
||
<p style="margin-top:20px"><b>核心挑战</b>:B、M、N、K 四个维度都可能很大或很小,必须在<span class="hl">32 个 AIC 核</span>上高效并行完成计算</p>
|
||
<p class="sub">一个 case 由 (B, M, N, K, dtype, 转置, 广播形态) 完全决定</p>
|
||
</div>
|
||
|
||
<!-- Slide 3: 硬件背景 -->
|
||
<div class="slide" id="s3">
|
||
<h2>2. 硬件基础:昇腾 950PR</h2>
|
||
<table>
|
||
<tr><th>规格</th><th>数值</th><th>对 tiling 的意义</th></tr>
|
||
<tr><td>AIC / AIV 核数</td><td class="hl">32 / 64(1:2)</td><td>核间并行度上限 C=32</td></tr>
|
||
<tr><td>Cube 算力 BF16</td><td class="hl">486 TFLOPS</td><td>算存比分子</td></tr>
|
||
<tr><td>GM 带宽</td><td class="hl">1.6 TB/s(读写共享)</td><td>访存 Bound 分母</td></tr>
|
||
<tr><td>L2 Cache</td><td class="hl">128MB / 5.2 TB/s</td><td>重复读取的吸收层</td></tr>
|
||
<tr><td>L1 / L0A / L0B / L0C</td><td class="hl">512KB / 64KB / 64KB / 256KB</td><td>核内分块的容量约束</td></tr>
|
||
</table>
|
||
<p style="margin-top:16px"><b>关键关系</b>:L2(5.2TB/s)→ L1(512KB)→ L0A/B(64KB)→ Cube(16×16×16 一拍)→ L0C(256KB)→ Fixpipe → GM</p>
|
||
<p class="sub">GM 带宽 1.6TB/s 相对 L2 的 5.2TB/s 是瓶颈——数据复用就是一切</p>
|
||
</div>
|
||
|
||
<!-- Slide 4: 性能模型 -->
|
||
<div class="slide" id="s4">
|
||
<h2>3. 什么叫"最优"?</h2>
|
||
<div class="eq">T_total = max(T_MMAD, T_MTE2, T_MTE1, T_Fixpipe [, T_Reduce])</div>
|
||
<p style="margin-top:16px"><b>总时延 = 流水线最慢的一级</b></p>
|
||
<p>核内多级流水并行:Cube 计算(MMAD)、GM→L1 搬移(MTE2)、L1→L0 搬移(MTE1)、L0C 写出(Fixpipe)</p>
|
||
<p style="margin-top:16px"><b class="hl">瓶颈交换</b>:搬移是瓶颈时,可牺牲算力换搬移效率;计算是瓶颈时,可牺牲搬移换计算效率</p>
|
||
<p style="margin-top:12px">算存比:<span class="eq">AI = 2MN/(M+N)</span> FLOP/元素</p>
|
||
<p>16bit 平衡点:<span class="eq">R₁₆ = 486 TFLOPS / (1.6TB/s ÷ 2B) ≈ 607.5</span> FLOP/元素</p>
|
||
<p>AI < R₁₆ → 访存 Bound(瓶颈在搬移)|AI > R₁₆ → 计算 Bound(瓶颈在 Cube)</p>
|
||
</div>
|
||
|
||
<!-- Slide 5: 分块本质 -->
|
||
<div class="slide" id="s5">
|
||
<h2>4. 分块计算的本质:4 维可切</h2>
|
||
<p>BMM 的实现 = 把数据按 B、M、N、K 切块,由 32 个 AIC 核并行 + 串行完成</p>
|
||
<p style="margin-top:16px"><b class="hl">核间怎么分这 4 个维度,就是分支划分的第一性问题</b></p>
|
||
<table>
|
||
<tr><th>切分维度</th><th>读入特征</th><th>计算特征</th><th>写出特征</th></tr>
|
||
<tr><td><span class="hl">切 B</span></td><td>核间零重复读</td><td>无核间依赖</td><td>无中间结果</td></tr>
|
||
<tr><td><span class="ct">切 M / 切 N</span></td><td>共享矩阵被多核重复读</td><td>无核间依赖</td><td>无中间结果</td></tr>
|
||
<tr><td><span class="note">切 K</span></td><td>零重复读</td><td>多核共同完成,有依赖</td><td>需核间归约</td></tr>
|
||
</table>
|
||
<p style="margin-top:16px">4 维任意非空子集共 <span class="hl">15 种</span>切分组合 → 完备枚举</p>
|
||
<p class="sub">为什么切 K 最贵?L0C 累加机制:核内切 K 时多轮 mmad 在 L0C 原地累加不出核;切到核间,部分和必须写出 workspace 再归约</p>
|
||
</div>
|
||
|
||
<!-- Slide 6: 价格表 -->
|
||
<div class="slide" id="s6">
|
||
<h2>5. 切分维度的"价格表"</h2>
|
||
<div class="eq">cost(切 B) = 0 < cost(切 M/N) ≪ cost(切 K)</div>
|
||
<p style="margin-top:20px"><b class="hl">切 B 免费</b>:零重复读、零依赖、零中间写出——BMM 语义就是逐 batch 独立</p>
|
||
<p><b class="ct">切 M/N 廉价</b>:共享矩阵被重复读,但 128MB L2(5.2TB/s)吸收大部分代价</p>
|
||
<p><b class="note">切 K 昂贵</b>:归约流量 ∝ 切 K 份数 × 输出量,且引入核间同步——结构性代价</p>
|
||
<p style="margin-top:24px"><b>整条分支决策树就是一句话:</b></p>
|
||
<p style="font-size:26px;color:#fbbf24;text-align:center">按价格从低到高购买并行度,买不够才加价</p>
|
||
</div>
|
||
|
||
<!-- Slide 7: 分支推导 -->
|
||
<div class="slide" id="s7">
|
||
<h2>6. 从价格表到 7 大分支</h2>
|
||
<div class="code">第0层:K=0/1 → AIV 向量通路(Cube 无用)
|
||
BatchA=1 或 BatchB=1 → 折叠转普通 Matmul
|
||
|
||
第1层:B ≥ 32(切 B 可满核)
|
||
M×N 大 → IterBatch(逐 batch 算)
|
||
M×N 小 → MergeBatch(多 batch 合并成大 tile 算)
|
||
|
||
第2层:B < 32,P = B·MN·4B/L0C ≥ 32
|
||
→ ASW_Basic(切 M/N 补并行,重复读交 L2+swizzle 吸收)
|
||
|
||
第3层:P < 32(B/M/N 都填不满核)
|
||
K 大 → StreamK(切 K,付归约代价)
|
||
K 小 → 降核 ASW(只用 ⌈P⌉ 个核,其余闲置)</div>
|
||
<p style="margin-top:12px">7 大路径:<span class="tag">特殊(AIV)</span><span class="tag">转Matmul</span><span class="tag">IterBatch</span><span class="tag">MergeBatch</span><span class="tag">ASW_Basic</span><span class="tag">StreamK</span><span class="tag">降核ASW</span></p>
|
||
</div>
|
||
|
||
<!-- Slide 8: MergeBatch -->
|
||
<div class="slide" id="s8">
|
||
<h2>7. MergeBatch — 多 batch 合并计算</h2>
|
||
<p><b>思路</b>:单 batch M×N 太小时,把 b 个 batch 拼成 [bM,K]@[K,bN] 大矩阵,</p>
|
||
<p>算完取块对角线得各 batch 结果。交叉项被丢弃,浪费比例 (b−1)/b</p>
|
||
<p style="margin-top:12px"><b class="hl">为什么允许浪费?</b> 进这个分支的 case 必然是访存 Bound,瓶颈在搬移</p>
|
||
<p>不是在计算——浪费的算力被搬移时延掩盖,用闲置算力换搬移效率</p>
|
||
<p style="margin-top:16px"><b>进入条件精要</b>:</p>
|
||
<ul>
|
||
<li>每核 batch 数 ≥ 4(2 组 × 合并下限 b₀=2,组间乒乓)</li>
|
||
<li>合并块输出 ≤ L0C(b₀²·MN·4B·2 ≤ 256KB)</li>
|
||
<li>单核搬移总量 ≥ 480KB(保证 GM 带宽利用率)</li>
|
||
<li>搬移 tile ≥ 16KB(单次搬移效率下限)</li>
|
||
<li>2MN/(M+N) < R₁₆/b₀(访存 Bound,保证浪费被掩盖)</li>
|
||
</ul>
|
||
<p class="sub">为何不允许 b_core=2?合并后每核仅 1 组,与 IterBatch(b_core=2) 总搬移时延相同,但多 50% 冗余计算——无收益</p>
|
||
<p class="sub">典型:B=128, M=N=64, K=512 → MergeBatch;K=256 → 单核搬移不够 480KB → IterBatch</p>
|
||
</div>
|
||
|
||
<!-- Slide 9: IterBatch -->
|
||
<div class="slide" id="s9">
|
||
<h2>8. IterBatch — 逐 batch 计算</h2>
|
||
<p><b>思路</b>:核间切 B,核内逐个 batch 做标准 Matmul。无浪费、无跨 batch 依赖</p>
|
||
<p style="margin-top:12px"><b>进入条件精要</b>:B ≥ 32;负载均衡;L1 四形态之一满足</p>
|
||
<p style="margin-top:10px"><b class="hl">关键:能否进 IterBatch 不由算存比判定</b></p>
|
||
<p>即使计算 Bound,L1 放不下完整 M、N 维输入 → 单 batch 内部重复读 → 额外搬移可能把算子重新拖回访存 Bound</p>
|
||
<p style="margin-top:10px"><b>L1 四形态</b>:</p>
|
||
<ul>
|
||
<li>a) 单 batch 全驻留(b_core=1 且 MK+KN ≤ L1)</li>
|
||
<li>b) 双 batch 乒乓(b_core>1 且 2(MK+KN) ≤ L1)</li>
|
||
<li>c) 一侧驻留+对侧切 K(预算 L1 或 L1/2,b_core≥2 时半区预取下一 batch 驻留侧)</li>
|
||
<li>d) 两侧切 K(无缝兜底,驻留侧超 L1/2 时接管)</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Slide 10: StreamK -->
|
||
<div class="slide" id="s10">
|
||
<h2>9. StreamK — K 维核间切分</h2>
|
||
<p><b>思路</b>:B/M/N 都填不满核时,把 K 切给多个核各算一段,再归约</p>
|
||
<p style="margin-top:12px"><b>进入条件</b>:P = B·MN·4B/L0C < 16(=C/2);K/grid_K ≥ 128 元素(dValue 256B)</p>
|
||
<p class="sub">阈值取 C/2:grid_K≥2 时每块需 2 核,P×2 ≤ C 才放得下</p>
|
||
<p><b>归约代价</b>(按实现流程推导):</p>
|
||
<div class="code">第1步:grid_K 个 AIC 各算 K/grid_K 段,L0C 原地累加
|
||
第2步:fixpipe 写部分和到 workspace(驻留 L2,走 5.2TB/s 写口)
|
||
第3步:AIV 从 L2 读回各段部分和到 UB,向量求和,写回
|
||
(AIV 独立硬件,数据流 GM/L2→UB→AIV→UB→L2/GM)</div>
|
||
<p style="margin-top:10px">归约时延 = 写部分和 + AIV 读回 + AIV 求和 + 写回,四段之和</p>
|
||
<p>收益判据:T_Reduce < T_pipe(1−1/grid_K),T_pipe = max(T_MTE2, T_MMAD)</p>
|
||
<p>⟺ T_pipe > grid_K/(grid_K−1)·T_Reduce(α=grid_K/(grid_K−1),grid_K=2 时 α=2)</p>
|
||
<p class="sub">StreamK case 多为访存 Bound(AI < R₁₆),T_pipe = T_MTE2 是瓶颈</p>
|
||
<p style="margin-top:8px"><span class="eq">K > grid_K²/(grid_K−1) × 12</span> grid_K=2→K>49;4→K>66;8→K>112</p>
|
||
<p class="sub">源码 8192 = C×512B = dValue 推荐值在最大 grid_K=C 下的保障(条件2),非归约代价(条件3阈值仅 ~50~400)</p>
|
||
</div>
|
||
|
||
<!-- Slide 11: ASW 1 -->
|
||
<div class="slide" id="s11">
|
||
<h2>10. ASW_Basic — 通用框架(swizzle)</h2>
|
||
<p><b>思路</b>:不切 K,切 B/M/N 任意组合。最常命中的分支(35.2%)</p>
|
||
<p style="margin-top:12px"><b class="hl">swizzle 滑窗蛇形</b>:编排输出块的执行顺序,压缩每一波核的活跃工作集</p>
|
||
<p><b>窗口怎么取</b>:M 向每 W 块划窗,W = C 的 ≤ √C 的最大因子(32 核 → W=4)</p>
|
||
<p>一波核的 L2 足迹 ≈ (W·M^t·K + C/W·K·N^t)·dtype,W=√C 时最小</p>
|
||
<p><b>蛇形只在窗口行边界</b>:奇数窗口行 N 方向反向,使上一窗口末尾的 B 列带延续到下一窗口(LRU 热线),跨窗切换几乎零增量。窗内不蛇形——窗内 W 个 A 行块全程驻留 L2,扫序无关。</p>
|
||
<p style="margin-top:10px"><b>对比</b>:朴素行优先(Ñ=16 时)一波足迹 18 单位;滑窗 12 单位 → 缩小 1/3</p>
|
||
</div>
|
||
|
||
<!-- Slide 12: ASW 2 -->
|
||
<div class="slide" id="s12">
|
||
<h2>11. ASW_Basic — L2 切分 & 写出策略</h2>
|
||
<p><b>切的是输出平面</b>:把 M×N 切成大矩形块,每块的输入工作集 ≤ L2 可用空间</p>
|
||
<p style="margin-top:12px"><b class="hl">L2 是读写共用的</b>:输出驻留 L2 会压缩读入空间 → 写与读要联合决策</p>
|
||
<p style="margin-top:8px"><b>写出 Bound 先判定</b>:BW_out = C·Q₁₆·outB/(2K),K=256 时已超 GM 总线</p>
|
||
<p style="margin-top:8px"><b>三场景</b>:</p>
|
||
<ul>
|
||
<li><b>A</b>:S_in+S_out ≤ L2 → 全驻留,输出走 L2 异步回写(削峰)</li>
|
||
<li><b>B</b>:S_in ≤ L2 < S_in+S_out → 输入驻留保住 r_in=1,输出直写 GM(不占 L2)</li>
|
||
<li><b>C</b>:S_in > L2 → 必须切分,输出直写 GM,块内错位分核(对角线,同地址冲突 4→2)</li>
|
||
</ul>
|
||
<p class="sub">r_in = 1 含义:每个输入从 GM 只读一遍,后续复用全在 L2 命中</p>
|
||
</div>
|
||
|
||
<!-- Slide 13: 遍历验证 -->
|
||
<div class="slide" id="s13">
|
||
<h2>12. case 遍历验证:20736 个 case 全覆盖</h2>
|
||
<p>B∈[1,2048]、M,N,K∈[1,10240] 对数采样,按进入条件严格分类</p>
|
||
<table>
|
||
<tr><th>分支</th><th>占比</th><th>B 范围</th></tr>
|
||
<tr><td>ASW_Basic</td><td class="hl">35.2%</td><td>2~2048</td></tr>
|
||
<tr><td>IterBatch</td><td>21.9%</td><td>32~2048</td></tr>
|
||
<tr><td>降核 ASW</td><td>15.4%</td><td>2~128</td></tr>
|
||
<tr><td>特殊(AIV)</td><td>8.3%</td><td>任意</td></tr>
|
||
<tr><td>MergeBatch</td><td>8.1%</td><td>128~2048</td></tr>
|
||
<tr><td>转Matmul</td><td>7.6%</td><td>B=1</td></tr>
|
||
<tr><td>StreamK</td><td>3.5%</td><td>2~128</td></tr>
|
||
</table>
|
||
<p style="margin-top:12px"><b class="hl">7 个分支全部有真实 case 命中,无覆盖空洞</b></p>
|
||
<p class="sub">降核 ASW 是 P<C 且 K 小区域的理性归宿:并行度凑不满,碎切反而不如少用核</p>
|
||
</div>
|
||
|
||
<!-- Slide 14: 靠谱吗? -->
|
||
<div class="slide" id="s14">
|
||
<h2>这份分析靠谱吗?</h2>
|
||
<h3>✅ 根基扎实</h3>
|
||
<ul>
|
||
<li><b>源码级验证</b>:分支条件与 CANN ops-nn batch_mat_mul_v3 源码逐条对照(arch35 路径),MergeBatch/IterBatch/StreamK/ASW 的 IsCapable 条件均能在源码中找到对应,差异处已标注并给出理由</li>
|
||
<li><b>硬件规格准确</b>:950PR 架构白皮书(表3-1/表4-2)+ CANN 9.0 AscendC 编程文档(054/056/192篇等)为所有参数(L1 512KB、L0C 256KB、dValue 256B、GM 1.6TB/s)提供依据</li>
|
||
<li><b>数学推导闭环</b>:15 种切分组合完备枚举 → 价格表(免费/廉价/昂贵)→ 7 分支体系,极小性有反例表格验证</li>
|
||
</ul>
|
||
<h3>⚠️ 需要注意</h3>
|
||
<ul>
|
||
<li><b>经验常数</b>(min_TileSize=16KB、480KB、均衡率 0.8、CUBE_BOUND_RATIO 0.85 等)为该芯片档实测值,换芯片需重新标定</li>
|
||
<li><b>重叠区</b>(MergeBatch vs IterBatch 在 M×N 中段)的归属由端到端时延模型 $T_{total}$ 精确仲裁,文档条件给出的是"主场"</li>
|
||
<li><b>StreamK θ≈12</b> 基于 L2 5.2TB/s 推导,若 workspace 落 GM 则升至 ~97;源码 8192 门槛由 dValue 推荐值主导</li>
|
||
</ul>
|
||
<p style="margin-top:16px;font-size:24px;text-align:center;color:#38bdf8"><b>整体评价:逻辑体系完整,推导自洽,可指导工程实现</b></p>
|
||
</div>
|
||
|
||
<script>
|
||
let cur = 0;
|
||
const slides = document.querySelectorAll('.slide');
|
||
const N = slides.length;
|
||
function go(d) {
|
||
slides[cur].classList.remove('active');
|
||
cur = ((cur + d) % N + N) % N;
|
||
slides[cur].classList.add('active');
|
||
document.getElementById('pg').textContent = `${cur+1}/${N}`;
|
||
}
|
||
document.addEventListener('keydown', e => { if (e.key === 'ArrowRight') go(1); if (e.key === 'ArrowLeft') go(-1); });
|
||
</script>
|
||
</body>
|
||
</html> |