Fix #31/#32: 切B类GM每字节恰一次=V_in(去K切分整段上取) / ASW场景升级(单侧全驻留+对侧滑窗->S_B, S_C最小替换2D分组+窗口L2计账) / 06文档§3+Step5与docs/05同步

#31 IterBatch/MergeBatch: K切分各(batch,K段)互不重叠+驻留侧每batch一次+末段按实际剩余
    -> GM读取量=V_in(与L2容量无关), GM数据时延=V_in/W_GM; n_K仅决定DMA命令数(T_cmd)
    b64_m16_n256_k512 形态c: GM 25.07MB->17.83MB=V_in; 回归: 形态c/d非整除+L1绑定三类断言
#32 ASW: (1)S_B扩展单侧全驻留+对侧滑窗(a_b/b_b+2*对侧单块<=L2) -> GM=V_in, 6个场景C行回落S_B;
    (2)S_C在整L2容量约束下搜索最小GM=ceil(n_cnt/n_grp)a_b+ceil(m_cnt/m_grp)b_b(取代L2/2对半预算),
    并计组内窗口L2流量((n_cnt-ceil)a_b+(m_cnt-ceil)b_b), 与S_B'驻留命中走L2'口径一致;
    b8_m131072_n8192_k8192 GM倍率4.76x->3.88x(物理下界~3.9x, 双侧均超L2)
    大方形K行(如b128_m8192_n8192_k7168)由MMAD 253ms->MTE2(L2口)295ms: 共享块重复读1.38TB
    经L2读口5.2TB/s, 如实计账(原C窗口流量零计低估)
- docs/06 §3与Step5重写为S_A/S_B/S_C+两段链口径(旧r_in单段/除B/对半预算口径废弃)
- docs/05 R5/R6/§3.1/§4.1/§4.3/§5与docs/01、02(01_MergeBatch/02_IterBatch GM口径附注)同步
- tests 54/54; 压力seed7/6000+seed2024/4000: 0违规/0占位/0NaN/0GM<V_in; examples重生成0diff
This commit is contained in:
2026-09-04 17:12:47 +08:00
parent b9e07edc1d
commit 18f59599e7
11 changed files with 370 additions and 192 deletions

View File

@@ -56,6 +56,11 @@ $$T_{mb} = \underbrace{\frac{b_{core}}{b_0}\cdot n_K^m\cdot(T_{load}^m + T_{cmd}
L1 绑定情形搬移次数单次搬移量都与 IterBatch 相同只放大 drain——证明见 v1.1 §4.4
> **GM 数据量口径 (issue#31)**: 各 (合并组, K段) 的数据互不重叠, 每个输入字节恰好从 GM
> 读一次 —— K 截断与 L1 绑定两种情形的**芯片 GM 读取量都 = V_in** (末段按实际剩余计,
> 无 padding 上取)。上式的 T_load 级联只用于刻画命令/双缓冲调度结构: 数据时延按
> V_in/W_GM 计, n_K 只放大 DMA 命令项 (b_core/b₀ 或 b_core·n_K) × T_cmd。
## 5. MergeBatch vs IterBatch 净收益
$$\text{净收益} = \underbrace{b_{core}\Big(1-\frac{1}{b_0}\Big)T_{cmd}}_{\text{搬移命令节省}} - \underbrace{(b_0-1)(T_{comp}+T_{write})}_{\text{drain 惩罚}}$$

View File

@@ -40,6 +40,11 @@ $$T_{iter} = \underbrace{b_{core}\cdot n_K\cdot(T_{load} + T_{cmd})}_{\text{搬
每 batch 的 A[M,K]+B[K,N] 作为独立 DMA 操作搬入 L1源码 `ndNum = curIterBatchL1`,多块独立寻址)。
> **GM 数据量口径 (issue#31)**: 形态 a/b/c/d 的 K 段/驻留侧数据互不重叠、每个输入字节
> 恰好从 GM 读一次 (形态 c 的驻留侧每 batch 只搬一次; 切 K 末段按实际剩余计, 无 padding
> 上取) —— **芯片 GM 读取量 = V_in**, 与 L2 容量无关 (IterBatch 无 L2 级重复读)。
> n_K 只决定 DMA 命令数 (T_cmd 项) 与双缓冲调度, 不放大数据量; 数据时延按 V_in/W_GM 计。
## 6. 与 MergeBatch 的分界
见 [01_MergeBatch分支.md](01_MergeBatch分支.md) §4~5。IterBatch 在 **L1 绑定情形恒优**MergeBatch 仅在 K 截断且 b_core 足够大时胜。

View File

@@ -20,15 +20,29 @@ ASW_Basic 是 BMM 的**兜底分支**——核间切 M/N或混合切
## 3. 时延建模
核间切 M/N不切 K每核处理若干 [singleCoreM, singleCoreN] 输出块
核间切 M/N不切 K每核处理若干 [singleCoreM, singleCoreN] 输出块 batch
A 行块被 n_cnt 个列 tile 共享B 列块被 m_cnt 个行 tile 共享issue#24 用户口径
最新场景口径见 issue#32 docs/05 §4
$$T = \max(T_{MTE2},\; T_{MMAD},\; T_{FIX}) + T_{drain}$$
其中 `T_MMAD = 2BMNK/(C·Q16)``T_FIX = B·MN·outB/(C·W_pc)` 与分配策略无关——**分配策略只影响 T_MTE2**通过 L2 命中率影响有效 GM 带宽
- `T_MMAD = 2BMNK / (used·Q16(dtype))` —— 与分配策略无关Q16 按输入 dtype 分档 (issue#28)
- **MTE2 两段搬移链**issue#23/#31/#32GM 为读写共享总线:
- `t_gm = S_in^GM / W_GM`GM 直读量首读 + 落空重读与输出直写 GM 并发时
读写累加输出落点见 docs/05 §4.2 R4
- `t_l2 = S_in^L2 / W_L2`L2 重复读量共享块驻留后其余次读取5.2TB/s 读口独享
- MTE2 = t_gm + t_l2 + DMA 命令开销
- `T_FIX`R4 输出落点—— case 输入+输出 L2 时写 L2 写口异步回写不占算子时延
否则直写 GM 计入共享总线issue#30)。
$$T_{MTE2} = \frac{S_{in}^{GM}}{C\cdot BW_{pc}},\qquad S_{in}^{GM} = r_{in}\cdot S_{in}$$
**GM/L2 流量归属 —— L2 场景判定**与代码 `_l2_scene` 同源docs/05 §4.14.3:
S_A 整case全驻留 / S_B 单batch可驻留全驻留**或单侧全驻留 + 对侧滑窗**)→
GM = V_in 一次r_in=1共享块重复读全部命中 L2S_C 双侧均超 L2 最小替换 2D 分组
L2 容量约束下最小 GM组间共享块落空回 GM组内窗口复用按 L2 计账
`r_in` = 重复读倍率GM 输入流量/输入总量r_in1下界 1 表示每字节只从 GM 读一次后续复用全命中 L2)。**分配策略的全部目标就是让 r_in 尽量接近 1**。
`r_in` = GM 输入流量/输入总量r_in1下界 1 表示每字节只从 GM 读一次后续复用
全命中 L2)。**分配策略的全部目标就是让 r_in 尽量接近 1**S_B 已识别"单侧可全驻留"
调度不再把可驻留 case 错误地按分组放大 GM只有双侧都放不下 L2 S_Cr_in > 1。
## 4. 核间分配策略B→M→N 线性映射
@@ -67,17 +81,19 @@ $$\text{BaseM}\times\text{BaseN} = \frac{L0C}{2\times 4B} = 32768\ \text{元素}
同一波 C 个核所需的 A 行块 + B 列块集合是"活跃工作集",超 L2 就回 GM 读。swizzle 编排输出块执行顺序,把每一波的活跃工作集压到最小。窗口宽度 `W = max{d | d|C, d ≤ ⌊√C⌋}`C=32 时 W=4窗口内先扫 M、扫满 W 行进下一列 N奇数窗口行 N 向反向(蛇形)。
**Step 5: L2 分组(工作集超 L2 时**
**Step 5: L2 场景判定与分组make_plan/evaluate 共用 `_l2_scene`issue#24/#32**
S_in = B(MK+KN)·dtS_out = B·MN·outB两个不变量GM 流量下界 = S_in + S_outL2 读入可用空间 L2_read = L2 S_out^resident
记单 batch 输入 a_b = MK·dt、b_b = KN·dt整 case V_in = S_in、V_out = S_out
A 行块 block_a = a_b/m_cnt、B 列块 block_b = b_b/n_cnt。
| 场景 | 条件 | 策略 |
| 场景 | 条件 | GM / L2 计账(每 batch |
|---|---|---|
| A 全驻留 | S_in + S_out L2 | 输入读一遍r_in=1输出驻留 L2 异步回写无需切分 |
| B 输入能驻留加输出超了 | S_in L2 < S_in+S_out | **输入驻留、输出直写 GM**保住 r_in=1校验总线 (S_in+S_out)/T_MMAD W_GM |
| C 输入本身超 | S_in > L2 | 分组执行,每组输入工作集 ≤ L2输出直写 GM |
| S_A 整case全驻留 | V_in + V_out ≤ L2 | GM = a_b+b_b重复读 (n_cnt1)a_b+(m_cnt1)b_b 走 L2输出驻留 L2GM 写=0 |
| S_B 单batch可驻留 | a_b+b_b ≤ L2**或**单侧全驻留+对侧滑窗b_b+2·block_a ≤ L2 或 a_b+2·block_b ≤ L2 | GM = a_b+b_br_in=1重复读 (n_cnt1)a_b+(m_cnt1)b_b 全部命中 L2输出直写 GM |
| S_C 双侧超 L2 | 以上均不满足 | 容量 m_grp·block_a+n_grp·block_b ≤ L2 下最小化 GM = ⌈n_cnt/n_grp⌉·a_b + ⌈m_cnt/m_grp⌉·b_b组间落空计 GM窗口 (n_cnt⌈n_cnt/n_grp⌉)a_b+(m_cnt⌈m_cnt/m_grp⌉)b_b 计 L2 |
场景 C 分组:每组覆盖 M 向 m_grp、N 向 n_grp 个基本块,`m_grp = ⌊D/(2·sM)⌋``n_grp = ⌊D/(2·sN)⌋`D = L2/(B·K·dt);重复读倍率 `r_in = (n_grp·M + m_grp·N)/(M+N)`。块内错位分核(对角线分配)避免同地址并发读串行化。
> 注:早期口径(预算 D = L2/(B·K·dt) 且对半切、组内窗口流量零计)已废弃
> issue#24 除总 B 的矛盾、issue#32 对半预算与窗口零计失真);分组不再对半、窗口复用如实计 L2。
**Step 6: 核内 tiling**BaseM×BaseN×4B×DB ≤ L0CBaseM×k_L0×dt×2 ≤ L0Ak_L0×BaseN×dt×2 ≤ L0B内轴按 dValue 256B/512B 对齐。

View File

@@ -83,41 +83,47 @@ StreamK 归约是对 **fp32 部分和**求和 → AIV 归约恒按 fp32 档 (因
- **R3 (整 case 全驻留边界)**: V_in + V_out (StreamK 另加部分和 workspace) ≤ L2 时,
全程零逐出: GM_read = V_in (每字节一次), 全部重复读走 L2, 输出驻留 L2 (见 §4.2)。
- **R4 (输出落点)**: 见 §4.2。
- **R5 (输入工作集场景)**: batch 输入 ≤ L2 → batch 内 tile 共享块重复读按 L2 计
(A 行块被 n_cnt 个列 tile 复用 → (n_cnt1) 次 L2; B 列块被 m_cnt 个行 tile 复用 → (m_cnt1) 次 L2);
单 batch 输入 > L2 → 分组执行 (工作集思想, §4.3)。
- **R6 (已知简化, 文档标注)**: ① 组内窗口复用未另计 (保守); ② BatchA≠BatchB (均 ≥2, 如 2 vs 64)
的广播/混合 batch 结构按"每 batch 独立矩阵"计 GM = b·(a_b+b_b), 是 V_in 的**保守放大**
(真实为 V_in + 共享矩阵跨 batch 重复读 ≤ 该值), 文档标注不做特殊建模; ③ K 切分 (k_L1<K)
chunk 搬运按整段 k_L1 (含末段 padding 上取), GM V_in 恒成立
- **R5 (输入工作集场景)**: batch 内 tile 共享块 (A 行块被 n_cnt 个列 tile 复用 →
(n_cnt1) 次重复; B 列块被 m_cnt 个行 tile 复用 → (m_cnt1) 次) 的流量归属由 §4.1
场景判定: 可驻留时按 L2 读口计 (含**单侧全驻留+对侧滑窗**调度, issue#32);
双侧都放不下时按最小替换分组 (§4.3)。
- **R6 (已知简化, 文档标注)**: ① BatchA≠BatchB (均 ≥2, 如 2 vs 64) 的广播/混合 batch 结构
按"每 batch 独立矩阵"计 GM = b·(a_b+b_b), 是 V_in 的**保守放大**
(真实为 V_in + 共享矩阵跨 batch 重复读 ≤ 该值), 不做特殊建模;
② K 切分 (k_L1<K) 各段数据互不重叠: GM 按实际字节精确计 (每字节恰从 GM 读一次,
padding 上取; 切段数只影响 DMA 命令数/T_cmd 与双缓冲调度, §5 issue#31);
场景按单 batch 工作集判定, 多核波次并发窗口按 batch 粒度近似
### 3.1 逐分支 GM/L2 流量归属表 (现行模型正确性核查结果)
| 分支 | 结构 | GM 直读 | L2 重复读 | 核查 |
|---|---|---|---|---|
| IterBatch ( B) | batch 整驻留/ K; (batch, K段) 数据互不重叠 | V_in (+K padding) | 0 (L1 形态吸收核内复用) | GMV_in |
| MergeBatch | 合并组 (b0 batch) 一次搬入; K / K 均不跨段重读同一字节 | V_in (+K padding) | 0 | GMV_in |
| ASW ( M/N) | batch tile 共享行/列块 | 场景 B: V_in; 场景 C: r_gm·V_in | (n_cnt1a_b·b + (m_cnt1b_b·b (场景 A/B) | GMV_in (场景 C 只放大) |
| IterBatch ( B) | batch 整驻留/ K; (batch, K段) 数据互不重叠 | **V_in** (每字节恰一次, padding 上取, issue#31) | 0 (L1 形态吸收核内复用) | GM=V_in |
| MergeBatch | 合并组 (b0 batch) 一次搬入; K / K 均不跨段重读同一字节 | **V_in** (issue#31) | 0 | GM=V_in |
| ASW ( M/N) | batch tile 共享行/列块 | S_A/S_B: **V_in** (含单侧全驻留调度, issue#32); S_C: 最小替换分组 GM (≥V_in, 仅双侧超L2 >1) | S_A/S_B: b·[(n_cnt1)·a_b + (m_cnt1)·b_b]; S_C: 组内窗口计 L2 (issue#32) | ✓ GM≥V_in |
| StreamK | 组内 K 段零重复读; 组间共享块同 ASW | V_in (命中时) | 组间共享块 (命中时) | ✓ |
| 特殊分支 K=1 | AIV 通路, 每元素一次 | V_in | 0 | ✓ |
| 转Matmul | 折叠单次 GEMM | V_in | 0 (Matmul 精切未展开) | ✓ |
**计算层面 GM 均 ≥ V_in**, 用户看到的 "GM < 输入" 来自**字节列每核/芯片口径混用**
(MergeBatch/IterBatch 记每核值 ×32 才是整芯片; ASW/StreamK 记整芯片值), 不是少算
统一为整芯片口径 (修正项 ①), 并加不变量测试 (修正项 ②), 补齐 R3 case 边界 (修正项 ③)。
**整芯片口径统一后 (issue#29): GM 均 = V_in (无重复读结构) 或 ≥ V_in (S_C 双侧超 L2 的最小替换分组)**, 不变量 GM ≥ V_in 由测试锁死 (违反即 bug)。
---
## 4. 场景模型 (输入侧) 与输出落点 (issue #30)
## 4. 场景模型 (输入侧) 与输出落点 (issue #30 / #32)
### 4.1 场景判定 (对切 M/N 及切 B 分支共用; L2 为整芯片 128MB)
- **S_A case 全驻留**: V_in + V_out [+ workspace] L2 输出驻留 L2;
- **S_B batch 输入可驻留**: 不满足 S_A, a_b + b_b L2 输入 batch 内共享块重复读命中 L2;
- **S_C batch 输入超 L2**: a_b + b_b > L2 → 分组执行 (输入工作集切分), 组间落空回 GM。
- **S_A 整 case 全驻留**: V_in + V_out [+ workspace] ≤ L2 → 输出驻留 L2 (R4);
- **S_B 单 batch 可驻留**: 不满足 S_A, 但单 batch 输入可全驻留 (a_b + b_b ≤ L2)
**或单侧全驻留 + 对侧滑窗**: b_b + 2·block_a ≤ L2 或 a_b + 2·block_b ≤ L2
(block_a = a_b/m_cnt = A 行块字节, block_b = b_b/n_cnt = B 列块字节)
→ GM = V_in 一次, 共享块重复读全部命中 L2 读口; 输出直写 GM;
- **S_C 双侧均超 L2**: a_b、b_b 及其滑窗组合都放不下 → 最小替换 2D 分组 (§4.3)。
判定顺序: S_A → S_B → S_C。(原 #24 场景 A 的"单 batch 输入+输出可驻留"判定被 S_A 取代:
整 case 输出跨 batch 累积时单 batch 判定不可靠, 见 #30。)
判定顺序 S_A → S_B → S_C。S_B 从原"双侧全驻留"扩展出"单侧全驻留+对侧滑窗"调度
(issue#32): 大矩阵行块流式、小矩阵全驻留时, GM 仍 = V_in, 不再被分组模型成倍放大。
(原 #24 场景 A 的"单 batch 输入+输出可驻留"判定被 S_A 取代: 整 case 输出跨 batch
累积时单 batch 判定不可靠, 见 #30。)
### 4.2 R4 输出落点规则 (取代一切"恒直写 GM / 单 batch 判定驻留")
@@ -135,12 +141,19 @@ StreamK 归约是对 **fp32 部分和**求和 → AIV 归约恒按 fp32 档 (因
| ASW | 场景 A (单 batch in+out 驻留) 时 to_l2 | S_A (整 case) 时 to_l2; S_B/S_C 直写 GM |
| StreamK | 归约内最终写回恒走 L2 | 最终写回按 S_A(+workspace); 不满足时写 GM (drain 内按 GM 带宽) |
### 4.3 场景 C 分组工作集 (沿用 #24 公式, 语义重申)
### 4.3 场景 C: 最小替换 2D 分组 (issue#32)
单 batch 输入超 L2 → 以 L2 为单 batch 活动窗口预算 D = L2 / (K·dt) (元素),
组 = m_grp × n_grp 个 tile, 组间共享块复用落空回 GM:
r_gm = (⌈n_cnt/n_grp⌉·M + ⌈m_cnt/m_grp⌉·N)/(M+N), GM = r_gm·V_in;
组内窗口复用未另计 (保守, R6①)。分组追求"最小 L2 替换": 一次只让一组的工作集占 L2
S_C (双侧均不可全驻留) 时, 在**整 L2 容量约束**下搜索最小 GM 的分组
(取代旧版 "L2/2 对半预算 + 组内窗口流量零计" 口径; 每 batch 计算, 全 case ×b):
- 容量约束: m_grp·block_a + n_grp·block_b ≤ L2 (组工作集可占满整 L2);
- 目标: GM = ⌈n_cnt/n_grp⌉·a_b + ⌈m_cnt/m_grp⌉·b_b **最小**
(A 行块在其列组内一次 GM 首读、B 列块在其行组内一次 GM 首读; GM ≥ V_in);
- 窗口 L2: (n_cnt ⌈n_cnt/n_grp⌉)·a_b + (m_cnt ⌈m_cnt/m_grp⌉)·b_b
(组内共享块其余次复用走 L2 读口, 与 S_B 口径一致);
- 无可行分组 (单块对都超 L2) 时保守回落: 每共享块独立落 GM (⌈·⌉ = n_cnt/m_cnt), 窗口不计。
分组追求"最小 L2 替换": 一次只让一组的工作集占 L2, 组间共享块落空回 GM。
### 4.4 字节列与计数列语义 (修正 ①, 整芯片口径)
@@ -157,9 +170,9 @@ dma_cmd_count 为**单核**命令数 (各核 DMA 引擎并行执行, 墙钟 T_cm
| 分支 | GM 读 (芯片) | L2 读 (芯片) | 输出 |
|---|---|---|---|
| MergeBatch | V_in (K截断); V_in·ceil(K/k_L1)·k_L1/K (L1绑定 padding, 模型按整段计) | 0 | S_A→L2 写口; else GM |
| IterBatch | V_in (a/b 形态); 同上 padding 式 (c/d) | 0 | 同 MergeBatch |
| ASW 切M/N | S_A/B: V_in; S_C: r_gm·V_in | S_A/B: b·[(n_cnt1)·a_b + (m_cnt1)·b_b] | S_A→L2; else GM |
| MergeBatch | V_in (每字节恰一次; K 截断/L1 绑定均无重复读, issue#31) | 0 | S_A→L2 写口; else GM |
| IterBatch | V_in (a/b/c/d 各形态均每字节恰一次, issue#31) | 0 | 同 MergeBatch |
| ASW 切M/N | S_A/S_B: V_in; S_C: b·[⌈n_cnt/n_grp⌉·a_b + ⌈m_cnt/m_grp⌉·b_b] (最小替换分组) | S_A/S_B: b·[(n_cnt1)·a_b + (m_cnt1)·b_b]; S_C: b·[(n_cnt⌈n_cnt/n_grp⌉)·a_b + (m_cnt⌈m_cnt/m_grp⌉)·b_b] | S_A→L2; else GM |
| StreamK | V_in (组间共享命中) | b·[(n_cnt1)·a_b + (m_cnt1)·b_b] (命中时) | 最终写回: S_A(+ws)→L2; else GM |
| 特殊分支 | K=1: V_in; K=0: 0 | 0 | S_A→L2 写口; else GM (K=0 只有输出) |
| 转Matmul | V_in (折叠后) | 0 | S_A→L2; else GM |