Files
matmul-analysis/BMM算子优化分析_Release/MergeBatch_vs_IterBatch分析_v1.0.html
2026-08-26 11:05:56 +00:00

197 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MergeBatch vs IterBatch 分析</title>
<script>
MathJax = {
tex: {
inlineMath: [['$','$']],
displayMath: [['$$','$$']],
tags: 'ams',
processEscapes: true
}
};
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<style>
:root{--ink:#1f2933;--muted:#5f6b7a;--accent:#0b6bcb;--accent2:#0e9f6e;--line:#d9e2ec;--code-bg:#f4f6f9}
*{box-sizing:border-box}
body{font-family:"PingFang SC","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;color:var(--ink);background:#eef2f6;margin:0;line-height:1.8}
.page{max-width:1020px;margin:0 auto;padding:32px 44px 80px;background:#fff;box-shadow:0 0 24px rgba(0,0,0,.06)}
h1{font-size:28px;border-bottom:3px solid var(--accent);padding-bottom:12px;margin-top:8px}
h2{font-size:22px;margin-top:44px;border-left:6px solid var(--accent);padding-left:12px;color:#0b3d73}
h3{font-size:18px;margin-top:30px;color:#0b3d73;border-bottom:1px dashed var(--line);padding-bottom:6px}
h4{font-size:16px;margin-top:20px;color:#123}
table{border-collapse:collapse;width:100%;margin:14px 0;font-size:14px}
th,td{border:1px solid var(--line);padding:7px 10px;text-align:left;vertical-align:top}
th{background:#eaf2fb;color:#0b3d73}
tr:nth-child(even) td{background:#f8fafc}
code,pre{font-family:"JetBrains Mono",Consolas,Menlo,monospace;font-size:13px}
code{background:var(--code-bg);padding:1px 5px;border-radius:4px;color:#9d2c5e}
pre{background:var(--code-bg);border:1px solid var(--line);border-radius:8px;padding:14px;overflow-x:auto;line-height:1.55}
pre code{background:none;color:#243447;padding:0}
blockquote{background:#eafaf3;border-left:5px solid var(--accent2);padding:10px 16px;border-radius:0 8px 8px 0;margin:14px 0}
.math{background:#fafbfc;border:1.5px solid #c3d6ee;border-radius:10px;padding:10px 22px;margin:14px 0;overflow-x:auto}
ul.tight li,ol.tight li{margin:3px 0}
hr{border:none;border-top:1px solid var(--line);margin:24px 0}
</style>
</head>
<body>
<div class="page">
<h1>MergeBatch vs IterBatchBMM 小 tile 场景的两种实现路径分析</h1>
<blockquote>目标芯片:昇腾 950PRDAV_3510。理论分析基于《BMM 算子优化分析 v0.96》,源码参考 [cann-ops-nn](https://gitee.com/ascend/cann-ops-nn) 中 <code>matmul/batch_mat_mul_v3</code> 实现。</blockquote>
<hr>
<h2>一、问题定义</h2>
<p>BMMBatchMatMul当 B ≥ Cbatch 数 ≥ AIC 核数)时,核间切 B 是免费的——每核独立处理若干 batch无共享无依赖。核内的两种实现路径</p>
<ul class="tight">
<li><b>IterBatch</b>:逐 batch 处理——每 batch 独立搬入 L1、独立计算、独立写回</li>
<li><b>MergeBatch</b>:合并处理——把 $b_0$ 个 batch 的 $A[M,K]@B[K,N]$ 合并为 $[b_0M, K]@[K, b_0N]$ 的大矩阵乘,一次搬入 L1、一次计算、一次写回</li>
</ul>
<p>核心问题:<b>什么条件下 MergeBatch 优于 IterBatch</b></p>
<hr>
<h2>二、IterBatch 理论最优实现</h2>
<h3>2.1 执行模型</h3>
<p>核间切 B每核 $b_{core} = B/C$ 个 batch。核内逐 batch 做标准 Matmul</p>
<pre><code>对每 batch i ∈ [0, b_core):
GM→L1: 搬入 A_i[M, K] + B_i[K, N](或按 kL1 分块)
L1→L0→Cube: 计算 C_i[M, N]
Fixpipe: L0C→GM 写回 C_i</code></pre>
<h3>2.2 L1 驻留形态</h3>
<p>IterBatch 按 L1 容量分四种形态v0.96 §六):</p>
<table><tr><th>形态</th><th>条件</th><th>特征</th></tr>
<tr><td>a) 单 batch 全驻留</td><td>$b_{core}=1$$(MK+KN) \cdot dtype \le L1$</td><td>零重复读</td></tr>
<tr><td>b) 双 batch 乒乓</td><td>$b_{core}&gt;1$$2(MK+KN) \cdot dtype \le L1$</td><td>batch 间流水掩盖</td></tr>
<tr><td>c) 一侧驻留+对侧切 K</td><td>$MK \cdot dtype \le L1/2$(驻留侧)</td><td>驻留侧零重复读</td></tr>
<tr><td>d) 两侧都切 K</td><td>兜底</td><td>两侧都有 K 段级重复读</td></tr></table>
<h3>2.3 实现方案</h3>
<ul class="tight">
<li><b>L0 tile</b>BaseM × BaseN 尽量用满 L0C32768 元素双缓冲baseK 由 L0A/L0B 容量决定</li>
<li><b>L1 tile</b>:按形态选择 kL1须满足 $k_{L1} \cdot dtype \ge 256$BdValue</li>
<li><b>流水</b>fixpipe 开 unitflagbatch 间由 L0C 双缓冲自动交叠</li>
</ul>
<hr>
<h2>三、MergeBatch 理论最优实现</h2>
<h3>3.1 执行模型</h3>
<p>核间切 B同 IterBatch核内把 $b_0$ 个 batch 合并计算:</p>
<pre><code>对每合并组 g ∈ [0, b_core/b0):
GM→L1: 搬入 A'[b0·M, K] + B'[K, b0·N](单次 DMAndNum=1
L1→L0→Cube: 计算 C'[b0·M, b0·N]
Fixpipe: L0C→GM 写回(只取对角块,丢弃交叉项)</code></pre>
<p>交叉项 $(b_0^2 - b_0) \cdot MN$ 被算出但丢弃——浪费比例 $(b_0-1)/b_0$。进入该分支的 case 必然访存 Bound条件 5 保证),浪费的算力被搬移时延掩盖。</p>
<h3>3.2 进入条件</h3>
<p>同时满足($b_0$ = 最小合并数,取 2</p>
<ol class="tight">
<li>$BatchA = BatchB$ 且 $b_{core} = B/C \ge 2b_0$</li>
<li>$2(b_0 M)(b_0 N) \cdot 4B \le L0C$(合并后输出放得下 L0C 双缓冲)</li>
<li>$b_{core}(MK+KN) \cdot dtype \ge min\_DatamountPerCore$(单核搬移量足够)</li>
<li>$\max(MK, KN) \cdot dtype \ge min\_TileSize$(搬移 tile 不太小)</li>
<li>$2MN/(M+N) &lt; R_{16}/b_0$(合并后仍访存 Bound</li>
</ol>
<h3>3.3 实现方案</h3>
<p><b>Step 1合并数 b₀L0C + 算存比双上限)</b></p>
<div class="math">$$
b_0 = \min\Big(\sqrt{\frac{L0C}{2 \cdot MN \cdot 4B}},\; \frac{R_{16}(M+N)}{2MN},\; b_{core}\Big)
$$</div>
<p>**Step 2L0 级 K 粒度 $k_{L0}$(由 b₀ 和 L0A/L0B 决定)**</p>
<div class="math">$$
k_{L0} = \min\Big(\frac{L0A}{2 b_0 M \cdot dtype},\; \frac{L0B}{2 b_0 N \cdot dtype}\Big) \text{ 向下 16 对齐}
$$</div>
<p>**Step 3L1 级 $k_{L1}$(先反推再截断)**</p>
<p>先令 $b_{L1}^* = b_0$,由 L1 容量反推 $k_{L1}^*$</p>
<div class="math">$$
k_{L1}^* = \frac{L1}{2 \cdot b_0 \cdot (M+N) \cdot dtype}
$$</div>
<p>然后取 $k_{L1} = \min(k_{L1}^*,\; K,\; 512B/dtype)$——不超过 KK 截断),也不超过 dValue 推荐值 512B。</p>
<p>**Step 4$b_{L1}$ 最大化**</p>
<div class="math">$$
b_{L1} = \min\Big(\frac{L1}{2 \cdot k_{L1} \cdot (M+N) \cdot dtype},\; b_{core}\Big)
$$</div>
<p>若 $k_{L1}^* &gt; 512B/dtype$$k_{L1}$ 被 512B 截断,省出的 L1 空间可容纳更多 batch$b_{L1} &gt; b_0$),提升 batch 间流水深度。</p>
<hr>
<h2>四、MergeBatch vs IterBatch 分界分析</h2>
<h3>4.1 核心差异GM→L1 搬移粒度</h3>
<p>从 kernel 侧源码可直接观察:</p>
<ul class="tight">
<li><b>IterBatch</b><code>block_mmad_iterbatch.h</code> CopyInA1<code>ndNum = curIterBatchL1</code>(多块独立寻址,<code>srcNdMatrixStride = M*K</code></li>
<li><b>MergeBatch</b><code>block_mmad_mergebatch.h</code> CopyInA1<code>ndNum = 1</code>(合并为单块连续搬移,<code>nValue = b0 × M</code></li>
</ul>
<p>每次 GM→L1 DMA 搬移有固定开销 $T_{cmd}$(描述符配置 + 地址生成 + 突发启动与搬移数据量无关。MergeBatch 把 $b_0$ 次搬移合并为 1 次,$T_{cmd}$ 节省 $b_0$ 倍。</p>
<h3>4.2 分情形分析</h3>
<p><b>K 截断情形</b>$k_{L1} = K$,整个 K 装入 L1 一块):</p>
<p>IterBatch 每 batch 一次 GM→L1 搬移MergeBatch 每合并 batch 一次(覆盖 $b_0$ 个 batch搬移次数少 $b_0$ 倍:</p>
<div class="math">$$
\Delta_K = \underbrace{(b_0-1)(T_{comp} + T_{write})}_{\text{drain 惩罚}} - \underbrace{b_{core}\Big(1-\frac{1}{b_0}\Big) T_{cmd}}_{\text{搬移命令节省}}
$$</div>
<p><b>L1 绑定情形</b>$k_{L1} &lt; K$K 需分块):</p>
<p>MergeBatch 合并后 tile 更大 → $k_{L1}^m = k_{L1}/b_0$ → $n_K^m = b_0 \cdot n_K$。搬移次数相同($b_{core} \cdot n_K$),每次搬移量也相同——<b>MergeBatch 无搬移优势</b>,只剩 drain 惩罚:</p>
<div class="math">$$
\Delta_L = (b_0-1)(T_{comp} + T_{write}) > 0
$$</div>
<p><b>L1 绑定情形 MergeBatch 恒劣于 IterBatch</b></p>
<h3>4.3 统一分界条件</h3>
<div class="math">$$
\text{MergeBatch 最优} \iff k_{L1} = K \;\land\; b_{core} > \frac{b_0 \cdot (T_{comp} + T_{write})}{T_{cmd}}
$$</div>
<p>即 MergeBatch 仅在 <b>K 截断</b>(小 M/N 使 $L1/(2(M+N) \cdot dtype) \ge K$)且 $b_{core}$ 足够大时才优于 IterBatch。</p>
<table><tr><th>维度</th><th>IterBatch</th><th>MergeBatch</th><th>差异</th></tr>
<tr><td>稳态搬移吞吐</td><td>相同</td><td>相同</td><td>总搬移量相同</td></tr>
<tr><td>GM→L1 搬移命令数</td><td>$b_{core}$ 次</td><td>$b_{core}/b_0$ 次</td><td>**MergeBatch 少 $b_0$ 倍** ← 核心优势</td></tr>
<tr><td>drain 暴露</td><td>$T_{comp} + T_{write}$</td><td>$b_0(T_{comp} + T_{write})$</td><td>IterBatch 少 $b_0$ 倍 ← 核心劣势</td></tr>
<tr><td>L0C 利用率</td><td></td><td></td><td>访存 Bound 下不影响时延</td></tr></table>
<h3>4.4 $T_{cmd}$ 的物理成因</h3>
<p>每次 GM→L1 DMA 搬移的固定开销包括Nd2Nz 描述符配置ndNum/nValue/dValue/srcStride 等 7 个字段写入 DMA 寄存器)、地址生成与突发启动、与 L1 buffer 的同步握手(<code>SetFlag&lt;MTE2_MTE1&gt;</code> / <code>WaitFlag&lt;MTE1_MTE2&gt;</code>)。量级估计为数十 ns精确值需实测标定。</p>
<hr>
<h2>五、与源码实现的对比</h2>
<h3>5.1 MergeBatch 源码(<code>batch_matmul_v3_mergebatch_basicapi_tiling.cpp</code></h3>
<p><b>IsCapable 条件</b></p>
<pre><code>// 源码https://gitee.com/ascend/cann-ops-nn
if (batchC &lt; MIN_BATCH_L0 * aicNum) return false; // B &lt; 128即 b_core &lt; 4
if (alignK &lt; 64 || M &gt; N) return false; // K ≥ 64M ≤ N
if (L0 buffer check with b0=4) return false; // L0C 容量</code></pre>
<p><b>对比分析</b></p>
<table><tr><th>维度</th><th>理论</th><th>源码</th><th>差异</th></tr>
<tr><td>合并数 b₀</td><td>min(L0C 上限, 算存比上限, b_core)</td><td>MIN_BATCH_L0 = 4固定实际由多项式动态求解</td><td>源码 b₀=4 是硬编码下限,实际值由 L0C 容量动态计算</td></tr>
<tr><td>b_core 下限</td><td>≥ 2b₀ = 4</td><td>≥ 4batchC ≥ 128</td><td>一致</td></tr>
<tr><td>L0C 约束</td><td>2(b₀M)(b₀N)·4B ≤ L0C</td><td>tempAlignM × tempAlignN × 4B × 2 ≤ L0C</td><td>一致</td></tr>
<tr><td>搬移量约束</td><td>b_core(MK+KN)·dtype ≥ 480KB</td><td><b></b></td><td>源码缺少</td></tr>
<tr><td>tile 大小约束</td><td>max(MK,KN)·dtype ≥ 16KB</td><td><b></b></td><td>源码缺少</td></tr>
<tr><td>算存比约束</td><td>2MN/(M+N) &lt; R₁₆/b₀</td><td><b></b></td><td>源码缺少</td></tr>
<tr><td>额外约束</td><td></td><td>K ≥ 64M ≤ N</td><td>源码独有</td></tr></table>
<p><b>结论</b>:源码的 MergeBatch 进入条件<b>偏宽</b>——缺少搬移量、tile 大小、算存比三条约束。可能导致不应进入的 case 被误捕获(如计算 Bound 的 case 进入 MergeBatch 后冗余计算成为瓶颈)。</p>
<h3>5.2 IterBatch 源码(<code>batch_matmul_v3_iterbatch_basicapi_tiling.cpp</code></h3>
<p><b>IsCapable 条件</b></p>
<pre><code>// 源码https://gitee.com/ascend/cann-ops-nn
if (batchC &lt;= aicNum) return false; // B ≤ 32 不进 IterBatch
if ((alignM*alignK + alignK*alignN)*dtype*2 &gt; L1) return false; // L1 双缓冲
if (!l0CanLoadBatch_ &amp;&amp; balanceRate &lt; 0.8) return false; // 负载均衡</code></pre>
<p><b>对比分析</b></p>
<table><tr><th>维度</th><th>理论</th><th>源码</th><th>差异</th></tr>
<tr><td>L1 形态</td><td>四种a/b/c/d</td><td>只覆盖形态 b</td><td>源码缺 a/c/d</td></tr>
<tr><td>B 下限</td><td>b_core ≥ 1</td><td>B &gt; 32b_core ≥ 2</td><td>源码排除了 b_core=1 的形态 a</td></tr>
<tr><td>负载均衡</td><td>B mod C ≥ minCoreNum</td><td>balanceRate ≥ 0.8</td><td>实现方式不同,目的一致</td></tr></table>
<p><b>结论</b>:源码的 IterBatch <b>只覆盖形态 b</b>(双 batch 乒乓),且要求 B &gt; C。形态 a/c/d 的 case 由 ASW/AL1/BL1 分支承接。</p>
<h3>5.3 综合评价</h3>
<p>理论分析的价值在于:</p>
<ol class="tight">
<li><b>分界条件</b>——源码无显式 MergeBatch vs IterBatch 分界,理论给出了 $k_{L1} = K \land b_{core} &gt; b_0(T_{comp}+T_{write})/T_{cmd}$ 的闭式条件</li>
<li><b>L1 绑定情形</b>——理论证明 MergeBatch 在 L1 绑定时恒劣于 IterBatch源码未区分</li>
<li><b>T_cmd 的物理意义</b>——GM→L1 DMA 命令固定开销,是 MergeBatch 优势的本质来源</li>
</ol>
<p>源码实现的价值在于:</p>
<ol class="tight">
<li><b>工程完备性</b>——负载均衡、格式检查、bias 处理等</li>
<li><b>cubeBound 模型</b>——经实测调优的 baseM/baseN 寻优</li>
<li><b>L2 Cache 管理</b>——100MB 阈值 + transConflict 控制</li>
</ol>
<hr>
<h2>参考文献</h2>
<ol class="tight">
<li>[昇腾 950 NPU 架构白皮书](https://public-download.obs.cn-east-2.myhuaweicloud.com/ascend/%E6%98%87%E8%85%BE950%20NPU%E6%9E%B6%E6%9E%84%E7%99%BD%E7%9A%AE%E4%B9%A6.pdf)华为技术有限公司2026</li>
<li>[CANN AscendC 算子开发——Matmul 高阶 API 使能 UnitFlag](https://www.hiascend.com/document/detail/zh/canncommercial/850/opdevg/Ascendcopdevg/atlas_ascendc_best_practices_10_10003.html)CANN 8.5.0</li>
<li>[cann-ops-nn 源码仓](https://gitee.com/ascend/cann-ops-nn)<code>matmul/batch_mat_mul_v3</code> 目录</li>
</ol>
</div>
</body>
</html>