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:
@@ -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,
|
||||
|
||||
@@ -45,6 +45,27 @@ GM = V_in 一次(r_in=1),共享块重复读全部命中 L2;S_C 双侧均
|
||||
全命中 L2)。**分配策略的全部目标就是让 r_in 尽量接近 1**:S_B 已识别"单侧可全驻留"
|
||||
调度(不再把可驻留 case 错误地按分组放大 GM);只有双侧都放不下 L2 时(S_C)r_in 才 > 1。
|
||||
|
||||
**尾轮残余 T_drain(闭式, issue#37)**:均匀分块下稳态聚合 ≡ `(n_wave−1+ρ)·T_block`
|
||||
(`N_blk/used = n_wave−1+ρ` 恒等),`T_drain` 只计尾轮结构相对稳态的残余;块级三段
|
||||
时延与 `_decide_tail` 主导项判定同源(L2 命中口径):
|
||||
|
||||
| 策略 / 主导项 | T_drain | 出处 |
|
||||
|---|---|---|
|
||||
| r = 0 | 0 | — |
|
||||
| A0(r>0,尾轮 r 核各 1 整块、C−r 核空转) | `(1−ρ)·T_block` | v1.5 §3.3 `T_A0 = n_wave·T_block` |
|
||||
| 面积型 A1b / 方案B | 0 | v1.5 §4.3 总量守恒严格相等 |
|
||||
| 周长型 A1b | `(√ρ−ρ)·T_load` | v1.5 §5 `T = (n_wave−1+√ρ)·T_load` |
|
||||
| 周长型 方案B | `(√(n_wave(n_wave−1+ρ)) − (n_wave−1+ρ))·T_load` | v1.5 §5 `T = √(n_wave(n_wave−1+ρ))·T_load` |
|
||||
|
||||
边界说明(**不计入模型**的两项, issue#37 决议仅标注):
|
||||
|
||||
- **首块填充/末块排空**:v1.91 §3.1 的 `T_drain = O(T_comp+T_write)` 在 UnitFlag
|
||||
16×16×16 细粒度流水下真实暴露为 granule 级小量(首 k 段搬入 + 末 granule 排空),
|
||||
量级未标定,不入模型——大 n_wave 时相对误差 O(1/n_wave);
|
||||
- **尾轮重切的流量放大**:方案B(全局 tile 缩 1/√g)与 A1b(尾轮区缩 √ρ)会真实
|
||||
增加搬移总量(周长和 ×√g / ×1/√ρ),字节列仍按主 tile 几何计账;仅影响周长型
|
||||
主导角区的精度(面积型 MTE2 非瓶颈,无影响)。
|
||||
|
||||
## 4. 核间分配策略:B→M→N 线性映射
|
||||
|
||||
**结论:B 优先分组在任何场景下都不优于线性映射**,根本原因:
|
||||
|
||||
@@ -931,5 +931,102 @@ class TestIssue36(unittest.TestCase):
|
||||
self.assertEqual(mb.timing.gm_read_bytes, ib.timing.gm_read_bytes)
|
||||
|
||||
|
||||
class TestIssue37(unittest.TestCase):
|
||||
"""issue#37: ASW_Basic evaluate 尾轮残余 drain 闭式化 (方案甲).
|
||||
|
||||
- P1: A0 + r>0 的 drain 由"全 case 三级 max"(≈2x 稳态) 修为 (1-ρ)·T_block;
|
||||
- P2: 周长型 A1b/方案B 补残余 (√ρ−ρ) / (√(n_wave(n_wave−1+ρ))−(n_wave−1+ρ))·T_load;
|
||||
- 面积型 A1b/方案B 与 r=0 残余恒 0 (v1.5 §4.3 严格相等);
|
||||
- 块级三段时延与 _decide_tail 同源 (_block_times, L2 命中口径).
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
from bmm_theory.branches.asw_basic import AswBasicBranch
|
||||
self.br = AswBasicBranch()
|
||||
self.s = ASCEND950PR
|
||||
|
||||
@staticmethod
|
||||
def _plan(case, sm, sn, m_cnt, n_cnt, strategy, r, n_wave):
|
||||
from bmm_theory.models import ImplPlan
|
||||
return ImplPlan(case_id=case.case_id, branch="ASW_Basic",
|
||||
used_core_num=32, m_cnt=m_cnt, n_cnt=n_cnt,
|
||||
single_core_m=sm, single_core_n=sn,
|
||||
single_core_k=case.k, k_l1=128,
|
||||
base_m=256, base_n=256, base_k=64,
|
||||
tail_strategy=strategy, tail_block_cnt=r,
|
||||
tail_wave_num=n_wave, fixpipe_unitflag=True,
|
||||
out_dtype_bytes=case.dtype_out_bytes)
|
||||
|
||||
def test_block_times_formula(self):
|
||||
# 块级三段 = v1.5 §2.1 口径 (k_L1 约掉, L2 命中带宽)
|
||||
case = mkcase(3, 1024, 1024, 1024)
|
||||
t_mm, t_mv, t_fx = self.br._block_times(case, 256, 256)
|
||||
self.assertAlmostEqual(t_mm, 2 * 256 * 256 * 1024
|
||||
/ self.s.q_cube("bf16", "bf16"))
|
||||
self.assertAlmostEqual(t_mv, 1024 * (256 + 256) * 2 / self.s.bw_l2_pc)
|
||||
self.assertAlmostEqual(t_fx, 256 * 256 * 2 / self.s.bw_pc)
|
||||
|
||||
def test_a0_drain_is_block_level_residual(self):
|
||||
# P1 修复: A0 + r>0 的 drain = (1-ρ)·T_block (修复前误用全 case 三级
|
||||
# max -> t_total ≈ 2x 稳态)
|
||||
case = mkcase(3, 1024, 1024, 1024)
|
||||
p = self._plan(case, 512, 128, 2, 8, "A0", r=16, n_wave=2)
|
||||
t = self.br.evaluate(case, p)
|
||||
t_block = max(self.br._block_times(case, 512, 128))
|
||||
self.assertAlmostEqual(t.t_drain, (1 - 16 / 32) * t_block)
|
||||
self.assertAlmostEqual(t.t_total, t.t_steady + t.t_drain)
|
||||
self.assertLess(t.t_drain, t.t_steady) # 不再 ~2x 稳态
|
||||
|
||||
def test_area_dominated_tail_residual_zero(self):
|
||||
# 面积型 (MMAD/FIX 主导): A1b/方案B 残余恒 0 (v1.5 §4.3 严格相等)
|
||||
case = mkcase(3, 1024, 1024, 1024)
|
||||
for strat in ("A1b", "方案B"):
|
||||
p = self._plan(case, 512, 128, 2, 8, strat, r=16, n_wave=2)
|
||||
t = self.br.evaluate(case, p)
|
||||
self.assertEqual(t.t_drain, 0.0, strat)
|
||||
self.assertAlmostEqual(t.t_total, t.t_steady)
|
||||
|
||||
def test_perimeter_a1b_residual(self):
|
||||
# P2: 周长型 (块级 MTE2 主导) + A1b: drain = (√ρ−ρ)·T_load
|
||||
case = mkcase(1, 640, 1408, 4096)
|
||||
t_mm, t_mv, t_fx = self.br._block_times(case, 64, 64)
|
||||
self.assertGreater(t_mv, max(t_mm, t_fx)) # 确认为周长型前提
|
||||
p = self._plan(case, 64, 64, 10, 22, "A1b", r=28, n_wave=7)
|
||||
t = self.br.evaluate(case, p)
|
||||
rho = 28 / 32
|
||||
self.assertAlmostEqual(t.t_drain, (rho ** 0.5 - rho) * t_mv)
|
||||
self.assertAlmostEqual(t.t_total, t.t_steady + t.t_drain)
|
||||
|
||||
def test_perimeter_planb_residual(self):
|
||||
# P2: 周长型 + 方案B: drain = (√(n_wave(n_wave−1+ρ))−(n_wave−1+ρ))·T_load
|
||||
case = mkcase(1, 640, 1408, 4096)
|
||||
p = self._plan(case, 64, 64, 10, 22, "方案B", r=28, n_wave=7)
|
||||
t = self.br.evaluate(case, p)
|
||||
t_mv = self.br._block_times(case, 64, 64)[1]
|
||||
rho, x = 28 / 32, 7 - 1 + 28 / 32
|
||||
self.assertAlmostEqual(t.t_drain, ((7 * x) ** 0.5 - x) * t_mv)
|
||||
self.assertGreater(t.t_drain, 0.0)
|
||||
|
||||
def test_r0_drain_zero(self):
|
||||
case = mkcase(3, 1024, 1024, 1024)
|
||||
p = self._plan(case, 512, 128, 2, 8, "A0", r=0, n_wave=2)
|
||||
self.assertEqual(self.br.evaluate(case, p).t_drain, 0.0)
|
||||
|
||||
def test_make_plan_perimeter_a1b_end_to_end(self):
|
||||
# 端到端 (make_plan 自产方案): 瘦长 case 周长型 + ρ≥ρ_dv -> A1b,
|
||||
# drain 与闭式一致 (_decide_tail 与 evaluate 同源)
|
||||
case = mkcase(33, 16, 8192, 7168)
|
||||
p = self.br.make_plan(case)
|
||||
self.assertGreater(p.tail_block_cnt, 0)
|
||||
self.assertEqual(p.tail_strategy, "A1b", p.note)
|
||||
t_mm, t_mv, t_fx = self.br._block_times(
|
||||
case, p.single_core_m, p.single_core_n)
|
||||
self.assertGreater(t_mv, max(t_mm, t_fx)) # 周长型前提
|
||||
t = self.br.evaluate(case, p)
|
||||
rho = p.tail_block_cnt / 32
|
||||
self.assertAlmostEqual(t.t_drain, (rho ** 0.5 - rho) * t_mv)
|
||||
self.assertAlmostEqual(t.t_total, t.t_steady + t.t_drain)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user