Fix #37: ASW_Basic 尾轮残余 drain 闭式化 (方案甲)

- P1 (bug, evaluate 路径): A0+r>0 的 t_drain 由"全 case 三级 max"
  (t_total≈2x 稳态) 修为块级残余 (1-ρ)·T_block (v1.5 §3.3)
- P2: 周长型主导 + r>0 补尾轮残余: A1b (√ρ−ρ)·T_load;
  方案B (√(n_wave(n_wave−1+ρ))−(n_wave−1+ρ))·T_load (v1.5 §5);
  面积型与 r=0 残余恒 0 (§4.3 严格相等), recommend 稳态主口径不变
- 块级三段时延抽取 _block_times, _decide_tail 与 evaluate 同源
- P3/P4 仅文档标注 (docs/02_分支理论/06 §3): 首块填充/末块排空
  (UnitFlag 16-granule 级小量, 量级未标定) 与尾轮重切流量放大
  (√g / 1/√ρ) 不入模型
- tests: TestIssue37 七例锁数值 (81/81 通过); examples 44 行 0 diff;
  压力回归 seed7/6000+seed2024/4000 干净 (0 崩溃/NaN/违规/GM<V_in)
This commit is contained in:
2026-09-09 10:11:22 +08:00
parent b0b48b9073
commit f9d5da0c0c
3 changed files with 164 additions and 11 deletions

View File

@@ -382,6 +382,20 @@ class AswBasicBranch(Branch):
"note": f"最小替换分组 m_grp={mg}x n_grp={ng} (GM倍率{r:.2f}, "
f"窗口L2/batch={l2/1048576:.1f}MB)"}
# ------------------------------------------------------------------
def _block_times(self, case: BmmCase, sm: int, sn: int) -> tuple:
"""单块三段时延 (尾轮文档 v1.5 §2.1 口径: k_L1 稳态约掉, L2 命中带宽).
返回 (t_mmad_blk, t_mte2_blk, t_fix_blk); _decide_tail 主导项判定与
evaluate 尾轮残余 drain (issue#37) 同源共用.
"""
s = self.spec
qc = s.q_cube(case.dtype_a, case.dtype_b) # issue#28
t_mmad = 2 * sm * sn * case.k / qc
t_mte2 = case.k * (sm + sn) * case.dtype_in_bytes / s.bw_l2_pc
t_fix = sm * sn * case.dtype_out_bytes / s.bw_pc
return t_mmad, t_mte2, t_fix
# ------------------------------------------------------------------
def _decide_tail(self, case, sm, sn, n_blk, k_l1) -> dict:
"""尾轮策略决策 (v1.5 闭式流程). 默认方案 B, 周长型且 rho>=rho_dv 时 A1b."""
@@ -391,7 +405,6 @@ class AswBasicBranch(Branch):
r = n_blk % c
rho = r / c
dt = case.dtype_in_bytes
out_b = case.dtype_out_bytes
base = dict(r=r, n_wave=n_wave, tail_m_cnt=1, tail_n_cnt=1,
tail_m_main=0, tail_n_main=0)
@@ -399,12 +412,8 @@ class AswBasicBranch(Branch):
if r == 0:
return {**base, "strategy": "A0", "reason": "r=0 无尾轮"}
# 主导项判定
bw_eff = s.bw_l2_pc # L2 命中
qc = s.q_cube(case.dtype_a, case.dtype_b) # issue#28
t_mmad = 2 * sm * sn * case.k / qc
t_mte2 = case.k * (sm + sn) * dt / bw_eff
t_fix = sm * sn * out_b / s.bw_pc
# 主导项判定 (块级三段, 与 evaluate drain 同源 _block_times)
t_mmad, t_mte2, t_fix = self._block_times(case, sm, sn)
t_block = max(t_mmad, t_mte2, t_fix)
area_dominated = t_block != t_mte2 # 面积型 = MMAD 或 FIX 主导
@@ -455,7 +464,9 @@ class AswBasicBranch(Branch):
- 输出落点 R4 (issue#30): 仅 S_A (整 case 输入+输出 <= L2) 驻留 L2
(5.2 写口, GM 写 = 0); S_B/S_C 直写 GM —— GM 读写共享总线累加由
assemble 的 MTE2 链处理 (issue#23);
- 字节列整芯片口径 (issue#29); Cube 算力按输入 dtype (issue#28).
- 字节列整芯片口径 (issue#29); Cube 算力按输入 dtype (issue#28);
- t_drain = 尾轮残余闭式 (issue#37, v1.5 §3.3/§4.3/§5): A0 (1-ρ)·T_block;
周长型 A1b/方案B 残余见下; 面积型与 r=0 恒 0 (与稳态严格相等).
"""
s = self.spec
b = case.batch_c
@@ -484,10 +495,34 @@ class AswBasicBranch(Branch):
# ---- Fixpipe (R4) ----
t_fix = out_all / (used * (s.bw_l2_pc if to_l2 else s.bw_pc))
# drain: 尾轮暴露 (方案 B 已均匀重切, drain 小; A1b 尾轮凑满, drain 小; A0 尾轮 r 核空转)
# ---- drain: 尾轮残余时延 (issue#37, 尾轮 v1.5 §3.3/§4.3/§5 闭式) ----
# 稳态聚合 t_steady ≡ (n_wave-1+rho)·T_block (均匀分块下 N_blk/used 恒等),
# drain 只计尾轮结构相对该稳态的残余:
# A0 (r>0): (1-rho)·T_block (T_A0 = n_wave·T_block)
# 面积型 A1b/方案B: 0 (§4.3 总量守恒, 与稳态严格相等)
# 周长型 A1b: (sqrt(rho)-rho)·T_load (§5: (n_wave-1+√ρ)·T_load)
# 周长型 方案B: (√(n_wave(n_wave-1+rho))-(n_wave-1+rho))·T_load
# 块级时延与 _decide_tail 同源 (_block_times, L2 命中口径); 未建模策略
# (如 A1a) 维持原口径 0。首块填充/末块排空 (v1.91 §3.1 O(T_comp+T_write))
# 在 UnitFlag 16-granule 细粒度流水下为 granule 级小量, 量级未标定,
# 不入模型 (docs/02_分支理论/06 §3 标注)。
t_drain = 0.0
if plan.tail_strategy == "A0" and plan.tail_block_cnt > 0:
t_drain = max(t_mmad, t_gm + t_l2, t_fix) # 尾轮空转一个整块
r = plan.tail_block_cnt
if r > 0:
n_wave = plan.tail_wave_num if plan.tail_wave_num > 0 \
else ceil_div(b * m_cnt * n_cnt, used)
rho = min(r / used, 1.0)
t_mm_b, t_mv_b, t_fx_b = self._block_times(
case, plan.single_core_m, plan.single_core_n)
t_block = max(t_mm_b, t_mv_b, t_fx_b)
if plan.tail_strategy == "A0":
t_drain = (1.0 - rho) * t_block
elif t_block == t_mv_b: # 仅周长型主导有残余 (面积型严格 0)
if plan.tail_strategy == "A1b":
t_drain = (math.sqrt(rho) - rho) * t_mv_b
elif plan.tail_strategy == "方案B":
t_drain = (math.sqrt(n_wave * (n_wave - 1 + rho))
- (n_wave - 1 + rho)) * t_mv_b
return assemble_timing(
t_mte2_gm=t_gm, t_mte2_l2=t_l2, t_dma_cmd=0.0,