diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6011912 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +.pytest_cache/ +.venv/ +venv/ + +# 临时/调试文件 (避免误提交 issue 复现 csv、diff 产物等) +*.tmp +*.bak +*~ +*.swp + +# IDE / OS +.idea/ +.vscode/ +.DS_Store +Thumbs.db diff --git a/BMM/BMM_Theory/README.md b/BMM/BMM_Theory/README.md index be5be26..2833a98 100644 --- a/BMM/BMM_Theory/README.md +++ b/BMM/BMM_Theory/README.md @@ -76,17 +76,18 @@ BMM_Theory/ │ ├── special.py # 特殊分支 (K=0/1, AIV 通路) │ ├── stream_k.py # StreamK (切K + 归约) │ └── asw_basic.py # ASW_Basic (含降核/swizzle/L2分组/尾轮决策) -├── docs/ # 文档 (架构 + 理论梳理) +├── docs/ # 文档 (架构 + 理论梳理 + 软件测评) │ ├── 01_软件架构.md -│ └── 02_分支理论/ -│ ├── 00_总纲_分支决策树.md -│ ├── 01_MergeBatch分支.md -│ ├── 02_IterBatch分支.md -│ ├── 03_转Matmul分支.md -│ ├── 04_特殊分支.md -│ ├── 05_StreamK分支.md -│ ├── 06_ASW_Basic分支.md # 尾轮策略已内化为其必要环节 -│ └── 07_尾轮处理策略.md # 尾轮完整推导 (参考) +│ ├── 02_分支理论/ +│ │ ├── 00_总纲_分支决策树.md +│ │ ├── 01_MergeBatch分支.md +│ │ ├── 02_IterBatch分支.md +│ │ ├── 03_转Matmul分支.md +│ │ ├── 04_特殊分支.md +│ │ ├── 05_StreamK分支.md +│ │ ├── 06_ASW_Basic分支.md # 尾轮策略已内化为其必要环节 +│ │ └── 07_尾轮处理策略.md # 尾轮完整推导 (参考) +│ └── 03_测评报告/ # 外部测评报告 (v1.0/v2.0 及后续复评) ├── examples/ # 示例输入输出 └── tests/ # 单元测试 (固化文档边界 case + issue 回归) ``` diff --git a/BMM/BMM_Theory/bmm_theory/branches/merge_batch.py b/BMM/BMM_Theory/bmm_theory/branches/merge_batch.py index 1dd34e7..cd9bd13 100644 --- a/BMM/BMM_Theory/bmm_theory/branches/merge_batch.py +++ b/BMM/BMM_Theory/bmm_theory/branches/merge_batch.py @@ -94,10 +94,14 @@ class MergeBatchBranch(Branch): b = case.batch_c b_core = b // s.aic_num - # Step 1: 合并数 b0 (L0C + 算存比双上限, 尽量取 b_core 的因子) + # Step 1: 合并数 b0 (L0C + L0A/L0B + 算存比 + b_core 四类上限, 尽量取 b_core 的因子) + # L0A/L0B 上限 (issue#13): 合并 tile = (b0*M)x(b0*N), base_k 有 16 (fractal) 硬底, + # 须满足 b0*M*16*dt*2 <= L0A 且 b0*N*16*dt*2 <= L0B, 否则合并后 L0 tile 无法驻留. b0_l0c = math.sqrt(s.l0c_bytes / (2 * m * n * 4)) b0_ai = s.r16 * (m + n) / (2 * m * n) - b0_max = int(min(b0_l0c, b0_ai, b_core)) + b0_l0a = s.l0a_bytes / (2 * m * s.fractal * dt) + b0_l0b = s.l0b_bytes / (2 * n * s.fractal * dt) + b0_max = int(min(b0_l0c, b0_ai, b0_l0a, b0_l0b, b_core)) b0 = max(MIN_B0, self._factor_floor(b_core, b0_max)) # Step 2: L0 级 K 粒度 k_L0 diff --git a/BMM/BMM_Theory/bmm_theory/branches/special.py b/BMM/BMM_Theory/bmm_theory/branches/special.py index 2b765c7..095991c 100644 --- a/BMM/BMM_Theory/bmm_theory/branches/special.py +++ b/BMM/BMM_Theory/bmm_theory/branches/special.py @@ -24,11 +24,14 @@ class SpecialBranch(Branch): c1 = case.k <= 1 checks = [ConditionCheck("1_K<=1 (Cube 无用)", c1, f"K={case.k}")] if case.k == 1: - # K=1 触发 AIV 通路需 B >= 2*AIV核数 且单 batch 输入输出能驻留 UB - c2 = case.batch_c >= 2 * self.spec.aiv_num + # K=1 的 AIV 通路恒可用 (issue#12): B>=2*AIV 开 UB 乒乓; B<128 退化为 + # AIV 单缓冲 (无乒乓, 逐 batch 串行搬入), 不再是无方案空洞. + b = case.batch_c + pingpong = b >= 2 * self.spec.aiv_num + mode = "UB乒乓" if pingpong else "AIV单缓冲(逐batch串行, B<2*AIV)" checks.append(ConditionCheck( - "2_K=1的AIV触发: B >= 2*AIV核数 (开UB乒乓)", - c2, f"B={case.batch_c} vs {2*self.spec.aiv_num}")) + "2_K=1的AIV通路: 恒可用 (B>=128 开UB乒乓, 否则单缓冲)", + True, f"B={b}, 模式={mode}")) return checks # ------------------------------------------------------------------ @@ -36,11 +39,15 @@ class SpecialBranch(Branch): s = self.spec if case.k == 0: sub = "K=0纯写值" + mode = "" note = "无任何计算, C=bias 或 0, 纯 AIV 写值; 按行均分到 AIV 核" else: sub = "K=1逐元素乘" - note = ("退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; " - "走 AIV 通路 GM->UB->Mul->GM, UB 乒乓") + pingpong = case.batch_c >= 2 * s.aiv_num + mode = "UB乒乓" if pingpong else "AIV单缓冲" + note = (f"退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; " + f"走 AIV 通路 GM->UB->Mul->GM, {mode} " + f"({'B>=2*AIV 双batch乒乓流水' if pingpong else 'B<2*AIV 逐batch单缓冲串行'})") return ImplPlan( case_id=case.case_id, branch=self.name, used_core_num=s.aiv_num, # 用 AIV 核 @@ -48,7 +55,8 @@ class SpecialBranch(Branch): core_map="AIV 核间按行均分 (无 Cube tile 概念)", b_core=0, merge_b0=1, single_core_m=0, single_core_n=0, single_core_k=case.k, - k_l1=0, b_l1=1, l1_form="UB驻留(AIV)", + k_l1=0, b_l1=1, + l1_form="UB驻留(AIV)" if case.k == 0 else "UB驻留(AIV) " + mode, base_m=0, base_n=0, base_k=0, l2_policy_in="allocate", l2_policy_out="direct_gm", swizzle_w=0, workspace_bytes=0, diff --git a/BMM/BMM_Theory/bmm_theory/branches/stream_k.py b/BMM/BMM_Theory/bmm_theory/branches/stream_k.py index 321a85c..8b1455b 100644 --- a/BMM/BMM_Theory/bmm_theory/branches/stream_k.py +++ b/BMM/BMM_Theory/bmm_theory/branches/stream_k.py @@ -145,13 +145,14 @@ class StreamKBranch(Branch): t_mmad = t_mmad_tile / grid_k t_mte2 = t_mte2_tile / grid_k - # 归约: 部分和 4B 驻留 L2, AIV 归约 (含最终按 C dtype 写回) + # 归约: 部分和 4B 驻留 L2, AIV 归约 (含部分和写/读回/求和/最终按 C dtype 写回) + # 口径 (issue#11): 归约整体为串行追加 (t_drain=t_reduce, reduce_serial=True), + # 部分和写出已计入 eval_streamk_reduce 的 t_write_partial —— 稳态 Fixpipe 不再 + # 重复计账. 此前按 grid_k*tile*4B/单核带宽份额另计一次, 既重复计账又把整组 + # 部分和串行压到单核写口, 高估 grid_k 倍 (streamk_demo 曾虚高到 55us/FIXPIPE). t_reduce = eval_streamk_reduce(tile_elems, grid_k, out_b, s) - - # Fixpipe: 部分和写出按 4B (L0C dtype, 防精度丢失), 驻留 L2. - # 最终归约结果的 C dtype 写回已在 t_reduce 内计, 此处不重复 (issue#9 口径对齐). - fix_bytes = grid_k * tile_elems * 4 - t_fix = fix_bytes / s.bw_l2_pc + fix_bytes = 0.0 + t_fix = 0.0 flops_pc = 2.0 * tile_elems * k / grid_k gm_bytes = k * (2 * math.sqrt(tile_elems)) * dt / grid_k diff --git a/BMM/BMM_Theory/bmm_theory/evaluator.py b/BMM/BMM_Theory/bmm_theory/evaluator.py index 01a456b..06f78df 100644 --- a/BMM/BMM_Theory/bmm_theory/evaluator.py +++ b/BMM/BMM_Theory/bmm_theory/evaluator.py @@ -75,8 +75,18 @@ class PlanEvaluator: tips.append("瓶颈在 Cube 计算: 已接近理论算力上限, 检查是否有冗余计算 " "(MergeBatch 交叉项) 可消除") elif bn == "FIXPIPE": - tips.append("瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), " - "或评估输出驻留 L2 异步回写策略") + if plan.branch == "StreamK": + # StreamK 部分和按 L0C dtype 4B 防精度丢失, 不随 C 的 fp16/fp8 转换, + # dtype 减半提示不适用 (issue#14); 写账已并入归约, 需查归约侧配置 + tips.append("瓶颈标注在 Fixpipe: StreamK 的部分和写出已并入归约计账 " + "(4B 防精度丢失, 不可随 C dtype 减半), 请核查 L2 写口/" + "归约并行度(grid_K) 设置") + else: + tips.append("瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), " + "或评估输出驻留 L2 异步回写策略") + elif bn == "REDUCE": + tips.append("瓶颈在 StreamK 归约 (串行追加): 可增大 grid_K 摊薄归约 " + "或核对确定性要求是否允许 StreamK") if plan.branch == "MergeBatch" and plan.k_l1 < case.k: tips.append("警告: MergeBatch 处于 L1 绑定情形 (k_L1=2 禁用 StreamK # ---- 派生属性 ---- + def __post_init__(self): + """输入合法性校验 (issue#15): 非法维度/负值静默产出伪方案, 必须明确报错.""" + bad = [] + for nm, v, lo, ok0 in (("batch_a", self.batch_a, 1, False), + ("batch_b", self.batch_b, 1, False), + ("m", self.m, 1, False), + ("n", self.n, 1, False), + ("k", self.k, 0, True)): + if not isinstance(v, int): + bad.append(f"{nm}={v!r} 非整数") + elif v < lo or (v == 0 and not ok0): + bad.append(f"{nm}={v} 非法 (需 >= {lo})") + if bad: + raise ValueError("case 维度非法: " + "; ".join(bad) + + " (m/n/batch 必须为正, k 可为 0)") + for nm, dt in (("dtype_a", self.dtype_a), ("dtype_b", self.dtype_b), + ("dtype_c", self.dtype_c)): + if str(dt).strip().lower() not in DTYPE_BYTES: + raise ValueError(f"不支持的 dtype: {dt!r}, 支持 {sorted(DTYPE_BYTES)}") + @property def batch_c(self) -> int: return max(self.batch_a, self.batch_b) diff --git a/BMM/BMM_Theory/bmm_theory/router.py b/BMM/BMM_Theory/bmm_theory/router.py index d100781..86e7f09 100644 --- a/BMM/BMM_Theory/bmm_theory/router.py +++ b/BMM/BMM_Theory/bmm_theory/router.py @@ -78,11 +78,9 @@ class BranchRouter: mb = self.merge_batch.analyze(case) ib = self.iter_batch.analyze(case) - candidates = [] - if mb.capable: - candidates.append((self.merge_batch.name, mb)) - if ib.capable: - candidates.append((self.iter_batch.name, ib)) + # 候选表: [(分支名, BranchResult)], 顺序 = 仲裁优先级 + cand_map = {self.merge_batch.name: mb, self.iter_batch.name: ib} + capable = {n: r.capable for n, r in cand_map.items()} arbitration = "" if mb.capable and ib.capable: @@ -100,8 +98,8 @@ class BranchRouter: ) if win != lat_win: win = lat_win # 时延模型为最终裁决 - elif candidates: - win = candidates[0][0] + elif any(capable.values()): + win = next(n for n, v in capable.items() if v) arbitration = f"仅 {win} 条件满足" else: # 切B分支都不满足, 尝试 StreamK 再回落 ASW @@ -115,11 +113,37 @@ class BranchRouter: f"IterBatch未过: {ib.failed_conditions()}; " f"MergeBatch未过: {mb.failed_conditions()}") - chosen = mb if win == self.merge_batch.name else ib + # 可行性保障 (issue#13): 仲裁胜出方案必须通过约束自检, 否则按 + # (另一切B候选 -> StreamK -> ASW_Basic) 顺序回退到首个可行方案. + from .constraints import check_plan_constraints + + def _feasible(n): + r = cand_map[n] + return r.plan is not None and not check_plan_constraints(case, r.plan, self.spec) + + if _feasible(win): + chosen = cand_map[win] + else: + loser = self.merge_batch.name if win == self.iter_batch.name else self.iter_batch.name + fallback_note = (f"; 但 {win} 方案自检违规: " + f"{'; '.join(check_plan_constraints(case, cand_map[win].plan, self.spec))}") + if capable.get(loser) and _feasible(loser): + chosen, win = cand_map[loser], loser + fallback_note += f", 回退可行候选 {loser}" + else: + sk = self.stream_k.analyze(case) + if sk.capable and sk.plan is not None and \ + not check_plan_constraints(case, sk.plan, self.spec): + return self._wrap_checked(case, sk, arbitration + fallback_note + ", 落 StreamK") + asw = self.asw_basic.analyze(case) + if asw.plan is not None and not check_plan_constraints(case, asw.plan, self.spec): + return self._wrap_checked(case, asw, arbitration + fallback_note + ", 回落 ASW_Basic") + chosen, win = cand_map[win], win # 无可行方案: 保留原裁决, 由自检标注 + arbitration += fallback_note + result = BranchResult(capable=True, plan=chosen.plan, timing=chosen.timing) return self._wrap_checked(case, result, arbitration, - candidates={n: r.capable for n, r in - [(self.merge_batch.name, mb), (self.iter_batch.name, ib)]}) + candidates=capable) # ------------------------------------------------------------------ def _wrap_checked(self, case: BmmCase, result: BranchResult, note: str, @@ -155,15 +179,3 @@ class BranchRouter: return {"branch": branch, "plan": plan, "timing": None, "arbitration": "[无方案] " + note, "candidates": {}, "self_check_violations": []} - - # ------------------------------------------------------------------ - @staticmethod - def _wrap(result: BranchResult, note: str) -> dict: - return { - "branch": result.plan.branch if result.plan else "未知", - "plan": result.plan, - "timing": result.timing, - "arbitration": note + (f" | {result.note}" if result.note else ""), - "candidates": {}, - "self_check_violations": [], - } diff --git a/BMM/BMM_Theory/docs/02_分支理论/04_特殊分支.md b/BMM/BMM_Theory/docs/02_分支理论/04_特殊分支.md index fe49e7c..0f0e173 100644 --- a/BMM/BMM_Theory/docs/02_分支理论/04_特殊分支.md +++ b/BMM/BMM_Theory/docs/02_分支理论/04_特殊分支.md @@ -20,7 +20,8 @@ K 维度是 Cube(MMAD)存在的意义——`C = Σ_k A[..,k]·B[k,..]` 的 - 数据流:GM→UB(读 A、B)→ Mul → GM(写 C),全程 AIV; - 时延:`T = max(搬入, 搬出)`,AIV 算力远剩,瓶颈在搬移:`T ≈ B·(MK + KN + MN)·dt / W_GM`; -- **触发条件**:`B ≥ 2×AIV核数 = 128`(开 UB 乒乓需要每核至少 2 个 batch 块)且单 batch 输入输出能驻留 UB。 +- **触发条件**:`B ≥ 2×AIV核数 = 128`(开 UB 乒乓需要每核至少 2 个 batch 块)且单 batch 输入输出能驻留 UB; +- **B < 128 时并不无解**(issue#12):退化为 **AIV 单缓冲**——无乒乓、逐 batch 串行搬入计算,仍远优于 Cube 通路(K=1 时 Cube 16×16×16 浪费 15/16),只是流水掩盖能力下降。软件 `special.py` 按 `B ≥ 128` 自动选择"UB乒乓 / AIV单缓冲"模式。 ## 4. 软件处理 diff --git a/BMM/BMM_Theory/examples/result_evaluate.csv b/BMM/BMM_Theory/examples/result_evaluate.csv index 2078117..4f2e73a 100644 --- a/BMM/BMM_Theory/examples/result_evaluate.csv +++ b/BMM/BMM_Theory/examples/result_evaluate.csv @@ -1,11 +1,11 @@ case_id,batch_a,batch_b,m,n,k,dtype_a,dtype_b,dtype_c,trans_a,trans_b,has_bias,out_nd,deterministic_level,plan_case_id,plan_branch,plan_npu,plan_op,plan_used_core_num,plan_split_b,plan_m_cnt,plan_n_cnt,plan_grid_k,plan_core_map,plan_b_core,plan_merge_b0,plan_single_core_m,plan_single_core_n,plan_single_core_k,plan_k_l1,plan_b_l1,plan_l1_form,plan_base_m,plan_base_n,plan_base_k,plan_l2_policy_in,plan_l2_policy_out,plan_swizzle_w,plan_workspace_bytes,plan_tail_strategy,plan_tail_m_cnt,plan_tail_n_cnt,plan_tail_k_cnt,plan_tail_m_main,plan_tail_n_main,plan_tail_block_cnt,plan_tail_wave_num,plan_fixpipe_unitflag,plan_out_dtype_bytes,plan_note,gm_read_bytes,l2_read_bytes,t_mte2_gm,t_mte2_l2,t_mte2,dma_cmd_count,t_dma_cmd,cube_flops,t_mmad,fixpipe_bytes,t_fixpipe,t_reduce,t_steady,t_drain,t_total,bottleneck,feasible,violations,bound_type,advice to_matmul_demo,1,1,2048,2048,2048,bf16,bf16,bf16,False,False,False,True,0,to_matmul_demo,转Matmul,Ascend950PR,batch_mat_mul_v3,32,1,0,0,1,"折叠为 Matmul [2048,2048]x[2048,2048], 复用 Matmul 切分体系",0,1,0,0,2048,0,1,,0,0,0,,,0,0,转Matmul后由 Matmul 体系决定,1,1,1,0,0,0,0,True,2,"BatchB=1免费折叠: 左矩阵 [1,2048,2048] 视图折叠为 [2048,2048], 零重排零 split",16777216,0.0,1.048576e-05,0.0,1.048576e-05,0.0,0.0,17179869184.0,3.534952506995885e-05,8388608,5.24288e-06,0.0,3.534952506995885e-05,0.0,3.534952506995885e-05,MMAD,True,,计算Bound,"瓶颈在 Cube 计算: 已接近理论算力上限, 检查是否有冗余计算 (MergeBatch 交叉项) 可消除" special_k0_demo,128,128,256,256,0,bf16,bf16,bf16,False,False,False,True,0,special_k0_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,0,0,1,UB驻留(AIV),0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=0纯写值: 无任何计算, C=bias 或 0, 纯 AIV 写值; 按行均分到 AIV 核",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), 或评估输出驻留 L2 异步回写策略" -special_k1_demo,128,128,256,256,1,bf16,bf16,bf16,False,False,False,True,0,special_k1_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,1,0,1,UB驻留(AIV),0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=1逐元素乘: 退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; 走 AIV 通路 GM->UB->Mul->GM, UB 乒乓",131072,0.0,8.192e-08,0.0,8.192e-08,0.0,0.0,8388608.0,6.206060606060606e-07,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), 或评估输出驻留 L2 异步回写策略" +special_k1_demo,128,128,256,256,1,bf16,bf16,bf16,False,False,False,True,0,special_k1_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,1,0,1,UB驻留(AIV) UB乒乓,0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=1逐元素乘: 退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; 走 AIV 通路 GM->UB->Mul->GM, UB乒乓 (B>=2*AIV 双batch乒乓流水)",131072,0.0,8.192e-08,0.0,8.192e-08,0.0,0.0,8388608.0,6.206060606060606e-07,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), 或评估输出驻留 L2 异步回写策略" merge_demo_k_trunc,2048,2048,32,32,256,bf16,bf16,bf16,False,False,False,True,0,merge_demo_k_trunc,MergeBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B均分(核间零重复读零依赖),64,4,128,128,256,256,8,合并驻留,128,128,128,allocate(GM->L1随路驻留L2),direct_gm,0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"b0=4 (L0C上限5.7/算存比上限19.0/b_core=64); K截断; 合并后单次DMA搬入 A'[128,256]+B'[256,128]",2097152,0.0,4.194304e-05,0.0,4.2743039999999997e-05,16.0,8.000000000000001e-07,134217728.0,8.837381267489712e-06,131072,2.62144e-06,0.0,4.2743039999999997e-05,3.0192408230452674e-07,4.3044964082304525e-05,MTE2_GM,True,,访存Bound(GM),"瓶颈在 GM 搬入: 可考虑增大 tile 提升 dValue/单核搬移量, 或利用 L2 驻留吸收重复读 (MergeBatch/ASW swizzle 方向)" merge_iter_arbitrate,128,128,64,64,512,bf16,bf16,bf16,False,False,False,True,0,merge_iter_arbitrate,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,512,512,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=256KB <= L1,524288,0.0,1.048576e-05,0.0,1.0685759999999999e-05,4,2.0000000000000002e-07,16777216.0,1.104672658436214e-06,32768,6.5536e-07,0.0,1.0685759999999999e-05,4.400081646090535e-07,1.1125768164609053e-05,MTE2_GM,True,,访存Bound(GM),"瓶颈在 GM 搬入: 可考虑增大 tile 提升 dValue/单核搬移量, 或利用 L2 驻留吸收重复读 (MergeBatch/ASW swizzle 方向)" iter_demo_form_b,128,128,64,64,256,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_b,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,256,256,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=128KB <= L1,262144,0.0,5.24288e-06,0.0,5.4428799999999995e-06,4,2.0000000000000002e-07,8388608.0,5.52336329218107e-07,32768,6.5536e-07,0.0,5.4428799999999995e-06,3.0192408230452674e-07,5.744804082304526e-06,MTE2_GM,True,,访存Bound(GM),"瓶颈在 GM 搬入: 可考虑增大 tile 提升 dValue/单核搬移量, 或利用 L2 驻留吸收重复读 (MergeBatch/ASW swizzle 方向)" iter_demo_form_d,64,64,64,64,8192,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_d,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),2,1,64,64,8192,1024,1,d_两侧都切K,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"两侧都切K: k_L1=1024, K段成对流水, batch边界天然无缝",4194304,0.0,8.388608e-05,0.0,8.468608e-05,16,8.000000000000001e-07,134217728.0,8.837381267489712e-06,16384,3.2768e-07,0.0,8.468608e-05,7.16176329218107e-07,8.540225632921811e-05,MTE2_GM,True,,访存Bound(GM),"瓶颈在 GM 搬入: 可考虑增大 tile 提升 dValue/单核搬移量, 或利用 L2 驻留吸收重复读 (MergeBatch/ASW swizzle 方向)" -streamk_demo,4,4,128,128,10240,bf16,bf16,bf16,False,False,False,True,0,streamk_demo,StreamK,Ascend950PR,batch_mat_mul_v3,32,1,1,1,32,"B/M/N切出4块, 每块32核切K归约 (归约组内核c负责K段[c*K/32,(c+1)*K/32))",1,1,128,128,320,256,1,K段标准分块流水,128,128,64,allocate(部分和驻留L2),"resident(部分和4B驻留L2, 防精度丢失不随C的fp16/fp8转换)",0,8388608,grid_K=32路切K+归约,1,1,32,0,0,0,0,True,4,"P=1.00, grid_K=32, 部分和驻留L2按4B写出, AIV归约后按C dtype=2B写最终",327680.0,0.0,6.5536e-06,0.0,6.5536e-06,0.0,0.0,41943040.0,2.761681646090535e-06,8388608,5.162220307692308e-05,3.4067453613053613e-06,5.162220307692308e-05,3.4067453613053613e-06,5.5028948438228435e-05,FIXPIPE,True,,写出Bound,"瓶颈在 Fixpipe 写出: 检查输出 dtype (fp16/fp8 可减半写出量), 或评估输出驻留 L2 异步回写策略" +streamk_demo,4,4,128,128,10240,bf16,bf16,bf16,False,False,False,True,0,streamk_demo,StreamK,Ascend950PR,batch_mat_mul_v3,32,1,1,1,32,"B/M/N切出4块, 每块32核切K归约 (归约组内核c负责K段[c*K/32,(c+1)*K/32))",1,1,128,128,320,256,1,K段标准分块流水,128,128,64,allocate(部分和驻留L2),"resident(部分和4B驻留L2, 防精度丢失不随C的fp16/fp8转换)",0,8388608,grid_K=32路切K+归约,1,1,32,0,0,0,0,True,4,"P=1.00, grid_K=32, 部分和驻留L2按4B写出, AIV归约后按C dtype=2B写最终",327680.0,0.0,6.5536e-06,0.0,6.5536e-06,0.0,0.0,41943040.0,2.761681646090535e-06,0.0,0.0,3.4067453613053613e-06,6.5536e-06,3.4067453613053613e-06,9.960345361305361e-06,MTE2_GM,True,,访存Bound(GM),"瓶颈在 GM 搬入: 可考虑增大 tile 提升 dValue/单核搬移量, 或利用 L2 驻留吸收重复读 (MergeBatch/ASW swizzle 方向)" asw_demo_full,2,2,8192,8192,1024,bf16,bf16,bf16,False,False,False,True,0,asw_demo_full,ASW_Basic,Ascend950PR,batch_mat_mul_v3,32,1,47,47,1,B->M->N线性映射+ASW滑窗蛇形(W=4),0,1,176,176,1024,256,1,双缓冲驻留当前tile输入,176,176,80,allocate(输入驻留L2吸收重复读),direct_gm(输出直写GM不占L2),4,0,方案B,52,52,1,52,52,2,139,True,2,"L2场景B_输入驻留输出直写GM, r_in=1.00; 尾轮: 周长型主导, rho=0.06UB->Mul->GM, UB 乒乓",131072,0.0,8.192e-08,0.0,8.192e-08,0.0,0.0,8388608.0,6.206060606060606e-07,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"K=1逐元素乘, 走AIV向量通路" +special_k1_demo,128,128,256,256,1,bf16,bf16,bf16,False,False,False,True,0,special_k1_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,1,0,1,UB驻留(AIV) UB乒乓,0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=1逐元素乘: 退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; 走 AIV 通路 GM->UB->Mul->GM, UB乒乓 (B>=2*AIV 双batch乒乓流水)",131072,0.0,8.192e-08,0.0,8.192e-08,0.0,0.0,8388608.0,6.206060606060606e-07,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"K=1逐元素乘, 走AIV向量通路" merge_demo_k_trunc,2048,2048,32,32,256,bf16,bf16,bf16,False,False,False,True,0,merge_demo_k_trunc,MergeBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B均分(核间零重复读零依赖),64,4,128,128,256,256,8,合并驻留,128,128,128,allocate(GM->L1随路驻留L2),direct_gm,0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"b0=4 (L0C上限5.7/算存比上限19.0/b_core=64); K截断; 合并后单次DMA搬入 A'[128,256]+B'[256,128]",2097152,0.0,4.194304e-05,0.0,4.2743039999999997e-05,16.0,8.000000000000001e-07,134217728.0,8.837381267489712e-06,131072,2.62144e-06,0.0,4.2743039999999997e-05,3.0192408230452674e-07,4.3044964082304525e-05,MTE2_GM,True,,访存Bound(GM),"两分支均合法, 仲裁: [分界条件] MergeBatch最优=True (k_L1=K(截断); b_core=64 vs 阈值 b0*(T_comp+T_write)/T_cmd=6.0; drain惩罚=(b0-1)*(T_comp+T_write)=0.23us, 搬移节省=b_core*(1-1/b0)*T_cmd=2.40us); [时延模型] T_MergeBatch=43.04us vs T_IterBatch=45.22us -> MergeBatch更优; [裁决] MergeBatch" merge_iter_arbitrate,128,128,64,64,512,bf16,bf16,bf16,False,False,False,True,0,merge_iter_arbitrate,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,512,512,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=256KB <= L1,524288,0.0,1.048576e-05,0.0,1.0685759999999999e-05,4,2.0000000000000002e-07,16777216.0,1.104672658436214e-06,32768,6.5536e-07,0.0,1.0685759999999999e-05,4.400081646090535e-07,1.1125768164609053e-05,MTE2_GM,True,,访存Bound(GM),"两分支均合法, 仲裁: [分界条件] MergeBatch最优=False (k_L1=K(截断); b_core=4 vs 阈值 b0*(T_comp+T_write)/T_cmd=17.6; drain惩罚=(b0-1)*(T_comp+T_write)=0.44us, 搬移节省=b_core*(1-1/b0)*T_cmd=0.10us); [时延模型] T_MergeBatch=11.49us vs T_IterBatch=11.13us -> IterBatch更优; [裁决] IterBatch" iter_demo_form_b,128,128,64,64,256,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_b,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,256,256,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=128KB <= L1,262144,0.0,5.24288e-06,0.0,5.4428799999999995e-06,4,2.0000000000000002e-07,8388608.0,5.52336329218107e-07,32768,6.5536e-07,0.0,5.4428799999999995e-06,3.0192408230452674e-07,5.744804082304526e-06,MTE2_GM,True,,访存Bound(GM),仅 IterBatch 条件满足 iter_demo_form_d,64,64,64,64,8192,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_d,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),2,1,64,64,8192,1024,1,d_两侧都切K,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"两侧都切K: k_L1=1024, K段成对流水, batch边界天然无缝",4194304,0.0,8.388608e-05,0.0,8.468608e-05,16,8.000000000000001e-07,134217728.0,8.837381267489712e-06,16384,3.2768e-07,0.0,8.468608e-05,7.16176329218107e-07,8.540225632921811e-05,MTE2_GM,True,,访存Bound(GM),仅 IterBatch 条件满足 -streamk_demo,4,4,128,128,10240,bf16,bf16,bf16,False,False,False,True,0,streamk_demo,StreamK,Ascend950PR,batch_mat_mul_v3,32,1,1,1,32,"B/M/N切出4块, 每块32核切K归约 (归约组内核c负责K段[c*K/32,(c+1)*K/32))",1,1,128,128,320,256,1,K段标准分块流水,128,128,64,allocate(部分和驻留L2),"resident(部分和4B驻留L2, 防精度丢失不随C的fp16/fp8转换)",0,8388608,grid_K=32路切K+归约,1,1,32,0,0,0,0,True,4,"P=1.00, grid_K=32, 部分和驻留L2按4B写出, AIV归约后按C dtype=2B写最终",327680.0,0.0,6.5536e-06,0.0,6.5536e-06,0.0,0.0,41943040.0,2.761681646090535e-06,8388608,5.162220307692308e-05,3.4067453613053613e-06,5.162220307692308e-05,3.4067453613053613e-06,5.5028948438228435e-05,FIXPIPE,True,,写出Bound,"P<=C/2, B/M/N并行度买不满, 切K (grid_K=32)" +streamk_demo,4,4,128,128,10240,bf16,bf16,bf16,False,False,False,True,0,streamk_demo,StreamK,Ascend950PR,batch_mat_mul_v3,32,1,1,1,32,"B/M/N切出4块, 每块32核切K归约 (归约组内核c负责K段[c*K/32,(c+1)*K/32))",1,1,128,128,320,256,1,K段标准分块流水,128,128,64,allocate(部分和驻留L2),"resident(部分和4B驻留L2, 防精度丢失不随C的fp16/fp8转换)",0,8388608,grid_K=32路切K+归约,1,1,32,0,0,0,0,True,4,"P=1.00, grid_K=32, 部分和驻留L2按4B写出, AIV归约后按C dtype=2B写最终",327680.0,0.0,6.5536e-06,0.0,6.5536e-06,0.0,0.0,41943040.0,2.761681646090535e-06,0.0,0.0,3.4067453613053613e-06,6.5536e-06,3.4067453613053613e-06,9.960345361305361e-06,MTE2_GM,True,,访存Bound(GM),"P<=C/2, B/M/N并行度买不满, 切K (grid_K=32)" asw_demo_full,2,2,8192,8192,1024,bf16,bf16,bf16,False,False,False,True,0,asw_demo_full,ASW_Basic,Ascend950PR,batch_mat_mul_v3,32,1,47,47,1,B->M->N线性映射+ASW滑窗蛇形(W=4),0,1,176,176,1024,256,1,双缓冲驻留当前tile输入,176,176,80,allocate(输入驻留L2吸收重复读),direct_gm(输出直写GM不占L2),4,0,方案B,52,52,1,52,52,2,139,True,2,"L2场景B_输入驻留输出直写GM, r_in=1.00; 尾轮: 周长型主导, rho=0.06= 256B/dtype 且 grid_K>=2; 3_归约代价可接受) asw_demo_reduce_core,16,16,256,256,128,bf16,bf16,bf16,False,False,False,True,0,asw_demo_reduce_core,ASW_Basic_降核,Ascend950PR,batch_mat_mul_v3,16,1,1,1,1,"降核: 只用16核, 每核一个L0C满载输出块, 其余核闲置",0,1,256,256,128,128,1,标准核内流水,256,256,64,allocate,direct_gm,0,0,不涉及(每核一块无尾轮),1,1,1,0,0,0,0,True,2,"P=16.00= 256B/dtype 且 grid_K>=2) diff --git a/BMM/BMM_Theory/smoke.txt b/BMM/BMM_Theory/smoke.txt new file mode 100644 index 0000000..b56530e --- /dev/null +++ b/BMM/BMM_Theory/smoke.txt @@ -0,0 +1,41 @@ +=== to_matmul_demo: B=1 M=2048 N=2048 K=2048 bf16 -> [转Matmul] + 仲裁: BatchA=1或BatchB=1, 折叠转普通Matmul + 方案: 核数=32 切分=B1xM0xN0xK1 b_core=0 b0=1 k_L1=0 L1形态= + 时延: 总=35.35us 稳态=35.35 drain=0.00 | MTE2=10.49(GM=10.49+cmd=0.00) MMAD=35.35 FIX=5.24 | 瓶颈=MMAD +=== special_k0_demo: B=128 M=256 N=256 K=0 bf16 -> [特殊分支] + 仲裁: K=0纯写值 + 方案: 核数=64 切分=B1xM1xN1xK1 b_core=0 b0=1 k_L1=0 L1形态=UB驻留(AIV) + 时延: 总=10.49us 稳态=10.49 drain=0.00 | MTE2=0.00(GM=0.00+cmd=0.00) MMAD=0.00 FIX=10.49 | 瓶颈=FIXPIPE +=== special_k1_demo: B=128 M=256 N=256 K=1 bf16 -> [特殊分支] + 仲裁: K=1逐元素乘, 走AIV向量通路 + 方案: 核数=64 切分=B1xM1xN1xK1 b_core=0 b0=1 k_L1=0 L1形态=UB驻留(AIV) UB乒乓 + 时延: 总=10.49us 稳态=10.49 drain=0.00 | MTE2=0.08(GM=0.08+cmd=0.00) MMAD=0.62 FIX=10.49 | 瓶颈=FIXPIPE +=== merge_demo_k_trunc: B=2048 M=32 N=32 K=256 bf16 -> [MergeBatch] + 仲裁: 两分支均合法, 仲裁: [分界条件] MergeBatch最优=True (k_L1=K(截断); b_core=64 vs 阈值 b0*(T_comp+T_write)/T_cmd=6.0; drain惩罚=(b0-1)*(T_comp+T_write)=0.23us, 搬移节省=b_core*(1-1/b0)*T_cmd=2.40us); [时延模型] T_MergeBatch=43.04us vs T_IterBatch=45.22us -> MergeBatch更优; [裁决] MergeBatch + 方案: 核数=32 切分=B32xM1xN1xK1 b_core=64 b0=4 k_L1=256 L1形态=合并驻留 + 时延: 总=43.04us 稳态=42.74 drain=0.30 | MTE2=42.74(GM=41.94+cmd=0.80) MMAD=8.84 FIX=2.62 | 瓶颈=MTE2_GM +=== merge_iter_arbitrate: B=128 M=64 N=64 K=512 bf16 -> [IterBatch] + 仲裁: 两分支均合法, 仲裁: [分界条件] MergeBatch最优=False (k_L1=K(截断); b_core=4 vs 阈值 b0*(T_comp+T_write)/T_cmd=17.6; drain惩罚=(b0-1)*(T_comp+T_write)=0.44us, 搬移节省=b_core*(1-1/b0)*T_cmd=0.10us); [时延模型] T_MergeBatch=11.49us vs T_IterBatch=11.13us -> IterBatch更优; [裁决] IterBatch + 方案: 核数=32 切分=B32xM1xN1xK1 b_core=4 b0=1 k_L1=512 L1形态=b_双batch乒乓 + 时延: 总=11.13us 稳态=10.69 drain=0.44 | MTE2=10.69(GM=10.49+cmd=0.20) MMAD=1.10 FIX=0.66 | 瓶颈=MTE2_GM +=== iter_demo_form_b: B=128 M=64 N=64 K=256 bf16 -> [IterBatch] + 仲裁: 仅 IterBatch 条件满足 + 方案: 核数=32 切分=B32xM1xN1xK1 b_core=4 b0=1 k_L1=256 L1形态=b_双batch乒乓 + 时延: 总=5.74us 稳态=5.44 drain=0.30 | MTE2=5.44(GM=5.24+cmd=0.20) MMAD=0.55 FIX=0.66 | 瓶颈=MTE2_GM +=== iter_demo_form_d: B=64 M=64 N=64 K=8192 bf16 -> [IterBatch] + 仲裁: 仅 IterBatch 条件满足 + 方案: 核数=32 切分=B32xM1xN1xK1 b_core=2 b0=1 k_L1=1024 L1形态=d_两侧都切K + 时延: 总=85.40us 稳态=84.69 drain=0.72 | MTE2=84.69(GM=83.89+cmd=0.80) MMAD=8.84 FIX=0.33 | 瓶颈=MTE2_GM +=== streamk_demo: B=4 M=128 N=128 K=10240 bf16 -> [StreamK] + 仲裁: P<=C/2, B/M/N并行度买不满, 切K (grid_K=32) + 方案: 核数=32 切分=B1xM1xN1xK32 b_core=1 b0=1 k_L1=256 L1形态=K段标准分块流水 + 时延: 总=9.96us 稳态=6.55 drain=3.41 | MTE2=6.55(GM=6.55+cmd=0.00) MMAD=2.76 FIX=0.00 | 瓶颈=MTE2_GM +=== asw_demo_full: B=2 M=8192 N=8192 K=1024 bf16 -> [ASW_Basic] + 仲裁: ASW_Basic兜底 (StreamK未过: 1_并行缺口: P=B*MN*4B/L0C <= C/2; 2_单核K段下限: K/grid_K >= 256B/dtype 且 grid_K>=2; 3_归约代价可接受) + 方案: 核数=32 切分=B1xM47xN47xK1 b_core=0 b0=1 k_L1=256 L1形态=双缓冲驻留当前tile输入 + 时延: 总=565.59us 稳态=565.59 drain=0.00 | MTE2=41.94(GM=41.94+cmd=0.00) MMAD=565.59 FIX=167.77 | 瓶颈=MMAD +=== asw_demo_reduce_core: B=16 M=256 N=256 K=128 bf16 -> [ASW_Basic_降核] + 仲裁: ASW_Basic兜底 (StreamK未过: 2_单核K段下限: K/grid_K >= 256B/dtype 且 grid_K>=2) + 方案: 核数=16 切分=B1xM1xN1xK1 b_core=0 b0=1 k_L1=128 L1形态=标准核内流水 + 时延: 总=2.62us 稳态=2.62 drain=0.00 | MTE2=2.62(GM=2.62+cmd=0.00) MMAD=1.10 FIX=2.62 | 瓶颈=MTE2_GM +[recommend] 10 个 case -> t.csv diff --git a/BMM/BMM_Theory/t.csv b/BMM/BMM_Theory/t.csv new file mode 100644 index 0000000..b0383ce --- /dev/null +++ b/BMM/BMM_Theory/t.csv @@ -0,0 +1,11 @@ +case_id,batch_a,batch_b,m,n,k,dtype_a,dtype_b,dtype_c,trans_a,trans_b,has_bias,out_nd,deterministic_level,plan_case_id,plan_branch,plan_npu,plan_op,plan_used_core_num,plan_split_b,plan_m_cnt,plan_n_cnt,plan_grid_k,plan_core_map,plan_b_core,plan_merge_b0,plan_single_core_m,plan_single_core_n,plan_single_core_k,plan_k_l1,plan_b_l1,plan_l1_form,plan_base_m,plan_base_n,plan_base_k,plan_l2_policy_in,plan_l2_policy_out,plan_swizzle_w,plan_workspace_bytes,plan_tail_strategy,plan_tail_m_cnt,plan_tail_n_cnt,plan_tail_k_cnt,plan_tail_m_main,plan_tail_n_main,plan_tail_block_cnt,plan_tail_wave_num,plan_fixpipe_unitflag,plan_out_dtype_bytes,plan_note,gm_read_bytes,l2_read_bytes,t_mte2_gm,t_mte2_l2,t_mte2,dma_cmd_count,t_dma_cmd,cube_flops,t_mmad,fixpipe_bytes,t_fixpipe,t_reduce,t_steady,t_drain,t_total,bottleneck,feasible,violations,bound_type,advice +to_matmul_demo,1,1,2048,2048,2048,bf16,bf16,bf16,False,False,False,True,0,to_matmul_demo,转Matmul,Ascend950PR,batch_mat_mul_v3,32,1,0,0,1,"折叠为 Matmul [2048,2048]x[2048,2048], 复用 Matmul 切分体系",0,1,0,0,2048,0,1,,0,0,0,,,0,0,转Matmul后由 Matmul 体系决定,1,1,1,0,0,0,0,True,2,"BatchB=1免费折叠: 左矩阵 [1,2048,2048] 视图折叠为 [2048,2048], 零重排零 split",16777216,0.0,1.048576e-05,0.0,1.048576e-05,0.0,0.0,17179869184.0,3.534952506995885e-05,8388608,5.24288e-06,0.0,3.534952506995885e-05,0.0,3.534952506995885e-05,MMAD,True,,计算Bound,"BatchA=1或BatchB=1, 折叠转普通Matmul" +special_k0_demo,128,128,256,256,0,bf16,bf16,bf16,False,False,False,True,0,special_k0_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,0,0,1,UB驻留(AIV),0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=0纯写值: 无任何计算, C=bias 或 0, 纯 AIV 写值; 按行均分到 AIV 核",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,K=0纯写值 +special_k1_demo,128,128,256,256,1,bf16,bf16,bf16,False,False,False,True,0,special_k1_demo,特殊分支,Ascend950PR,batch_mat_mul_v3,64,1,1,1,1,AIV 核间按行均分 (无 Cube tile 概念),0,1,0,0,1,0,1,UB驻留(AIV) UB乒乓,0,0,0,allocate,direct_gm,0,0,不涉及(AIV逐元素),1,1,1,0,0,0,0,False,2,"K=1逐元素乘: 退化为 C=A⊙B 无累加深度, Cube 16x16x16 粒度浪费 15/16; 走 AIV 通路 GM->UB->Mul->GM, UB乒乓 (B>=2*AIV 双batch乒乓流水)",131072,0.0,8.192e-08,0.0,8.192e-08,0.0,0.0,8388608.0,6.206060606060606e-07,16777216,1.048576e-05,0.0,1.048576e-05,0.0,1.048576e-05,FIXPIPE,True,,写出Bound,"K=1逐元素乘, 走AIV向量通路" +merge_demo_k_trunc,2048,2048,32,32,256,bf16,bf16,bf16,False,False,False,True,0,merge_demo_k_trunc,MergeBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B均分(核间零重复读零依赖),64,4,128,128,256,256,8,合并驻留,128,128,128,allocate(GM->L1随路驻留L2),direct_gm,0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"b0=4 (L0C上限5.7/算存比上限19.0/b_core=64); K截断; 合并后单次DMA搬入 A'[128,256]+B'[256,128]",2097152,0.0,4.194304e-05,0.0,4.2743039999999997e-05,16.0,8.000000000000001e-07,134217728.0,8.837381267489712e-06,131072,2.62144e-06,0.0,4.2743039999999997e-05,3.0192408230452674e-07,4.3044964082304525e-05,MTE2_GM,True,,访存Bound(GM),"两分支均合法, 仲裁: [分界条件] MergeBatch最优=True (k_L1=K(截断); b_core=64 vs 阈值 b0*(T_comp+T_write)/T_cmd=6.0; drain惩罚=(b0-1)*(T_comp+T_write)=0.23us, 搬移节省=b_core*(1-1/b0)*T_cmd=2.40us); [时延模型] T_MergeBatch=43.04us vs T_IterBatch=45.22us -> MergeBatch更优; [裁决] MergeBatch" +merge_iter_arbitrate,128,128,64,64,512,bf16,bf16,bf16,False,False,False,True,0,merge_iter_arbitrate,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,512,512,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=256KB <= L1,524288,0.0,1.048576e-05,0.0,1.0685759999999999e-05,4,2.0000000000000002e-07,16777216.0,1.104672658436214e-06,32768,6.5536e-07,0.0,1.0685759999999999e-05,4.400081646090535e-07,1.1125768164609053e-05,MTE2_GM,True,,访存Bound(GM),"两分支均合法, 仲裁: [分界条件] MergeBatch最优=False (k_L1=K(截断); b_core=4 vs 阈值 b0*(T_comp+T_write)/T_cmd=17.6; drain惩罚=(b0-1)*(T_comp+T_write)=0.44us, 搬移节省=b_core*(1-1/b0)*T_cmd=0.10us); [时延模型] T_MergeBatch=11.49us vs T_IterBatch=11.13us -> IterBatch更优; [裁决] IterBatch" +iter_demo_form_b,128,128,64,64,256,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_b,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),4,1,64,64,256,256,2,b_双batch乒乓,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,双batch乒乓: 2*(MK+KN)*dtype=128KB <= L1,262144,0.0,5.24288e-06,0.0,5.4428799999999995e-06,4,2.0000000000000002e-07,8388608.0,5.52336329218107e-07,32768,6.5536e-07,0.0,5.4428799999999995e-06,3.0192408230452674e-07,5.744804082304526e-06,MTE2_GM,True,,访存Bound(GM),仅 IterBatch 条件满足 +iter_demo_form_d,64,64,64,64,8192,bf16,bf16,bf16,False,False,False,True,0,iter_demo_form_d,IterBatch,Ascend950PR,batch_mat_mul_v3,32,32,1,1,1,切B轮转分配(核间零重复读零依赖),2,1,64,64,8192,1024,1,d_两侧都切K,64,64,256,allocate(GM->L1随路驻留L2),"direct_gm(输出仅写一次,直写GM不占L2)",0,0,不涉及(核内不切M/N),1,1,1,0,0,0,0,True,2,"两侧都切K: k_L1=1024, K段成对流水, batch边界天然无缝",4194304,0.0,8.388608e-05,0.0,8.468608e-05,16,8.000000000000001e-07,134217728.0,8.837381267489712e-06,16384,3.2768e-07,0.0,8.468608e-05,7.16176329218107e-07,8.540225632921811e-05,MTE2_GM,True,,访存Bound(GM),仅 IterBatch 条件满足 +streamk_demo,4,4,128,128,10240,bf16,bf16,bf16,False,False,False,True,0,streamk_demo,StreamK,Ascend950PR,batch_mat_mul_v3,32,1,1,1,32,"B/M/N切出4块, 每块32核切K归约 (归约组内核c负责K段[c*K/32,(c+1)*K/32))",1,1,128,128,320,256,1,K段标准分块流水,128,128,64,allocate(部分和驻留L2),"resident(部分和4B驻留L2, 防精度丢失不随C的fp16/fp8转换)",0,8388608,grid_K=32路切K+归约,1,1,32,0,0,0,0,True,4,"P=1.00, grid_K=32, 部分和驻留L2按4B写出, AIV归约后按C dtype=2B写最终",327680.0,0.0,6.5536e-06,0.0,6.5536e-06,0.0,0.0,41943040.0,2.761681646090535e-06,0.0,0.0,3.4067453613053613e-06,6.5536e-06,3.4067453613053613e-06,9.960345361305361e-06,MTE2_GM,True,,访存Bound(GM),"P<=C/2, B/M/N并行度买不满, 切K (grid_K=32)" +asw_demo_full,2,2,8192,8192,1024,bf16,bf16,bf16,False,False,False,True,0,asw_demo_full,ASW_Basic,Ascend950PR,batch_mat_mul_v3,32,1,47,47,1,B->M->N线性映射+ASW滑窗蛇形(W=4),0,1,176,176,1024,256,1,双缓冲驻留当前tile输入,176,176,80,allocate(输入驻留L2吸收重复读),direct_gm(输出直写GM不占L2),4,0,方案B,52,52,1,52,52,2,139,True,2,"L2场景B_输入驻留输出直写GM, r_in=1.00; 尾轮: 周长型主导, rho=0.06= 256B/dtype 且 grid_K>=2; 3_归约代价可接受) +asw_demo_reduce_core,16,16,256,256,128,bf16,bf16,bf16,False,False,False,True,0,asw_demo_reduce_core,ASW_Basic_降核,Ascend950PR,batch_mat_mul_v3,16,1,1,1,1,"降核: 只用16核, 每核一个L0C满载输出块, 其余核闲置",0,1,256,256,128,128,1,标准核内流水,256,256,64,allocate,direct_gm,0,0,不涉及(每核一块无尾轮),1,1,1,0,0,0,0,True,2,"P=16.00= 256B/dtype 且 grid_K>=2) diff --git a/BMM/BMM_Theory/tests/test_branches.py b/BMM/BMM_Theory/tests/test_branches.py index 195d25e..329d2a1 100644 --- a/BMM/BMM_Theory/tests/test_branches.py +++ b/BMM/BMM_Theory/tests/test_branches.py @@ -150,12 +150,17 @@ class TestIssueRegression(unittest.TestCase): def setUp(self): self.router = BranchRouter() - def test_issue4_k1_small_batch_no_crash(self): - # issue#4 P0: K=1 且 B<128 不得崩溃, 应标注"暂无理论方案" - r = self.router.route(mkcase(64, 8192, 32, 1, dtype_a="int8", dtype_b="int8")) - self.assertIsNotNone(r["plan"]) # 占位方案, 不为 None - self.assertEqual(r["plan"].used_core_num, 0) # 标注无方案 - self.assertIn("暂无理论方案", r["arbitration"]) + def test_issue4_k1_small_batch_real_plan(self): + # issue#4/#12: K=1 且 B<128 不崩溃, 且给出 AIV 单缓冲真实方案 (不再是无方案占位) + case = mkcase(64, 8192, 32, 1, dtype_a="int8", dtype_b="int8") + r = self.router.route(case) + self.assertIsNotNone(r["plan"]) + self.assertEqual(r["branch"], "特殊分支") + self.assertEqual(r["plan"].used_core_num, 64) # AIV 核 + self.assertNotIn("暂无理论方案", r["arbitration"]) + self.assertIn("单缓冲", r["plan"].note) + from bmm_theory.constraints import check_plan_constraints + self.assertEqual(check_plan_constraints(case, r["plan"]), []) def test_issue5_asw_reduced_core_base_k_dtype_aware(self): # issue#5: ASW 降核 base_k 按 dtype 反推, fp32 不再 L0A 溢出 @@ -204,5 +209,62 @@ class TestIssueRegression(unittest.TestCase): self.assertNotEqual(r["branch"], "StreamK") +class TestIssueRegression2(unittest.TestCase): + """第二轮复评问题 (#11-#16) 回归.""" + + def setUp(self): + self.router = BranchRouter() + + def test_issue11_streamk_fixpipe_no_double_count(self): + # issue#11: 部分和写出只经 t_reduce 计账一次; 稳态 fixpipe 不得再计 + from bmm_theory.branches.stream_k import StreamKBranch + case = mkcase(4, 128, 128, 10240) + sk = StreamKBranch().analyze(case) + t = sk.timing + self.assertAlmostEqual(t.t_fixpipe, 0.0) # 归约串行口径下无稳态 fixpipe 账 + self.assertAlmostEqual(t.fixpipe_bytes, 0.0) + # 端到端 = max(MTE2, MMAD) + 归约, 不再虚高到 55us/FIXPIPE + expect = max(t.t_mte2, t.t_mmad) + t.t_reduce + self.assertAlmostEqual(t.t_total, expect) + self.assertEqual(t.bottleneck, "MTE2_GM") + + def test_issue12_k1_pingpong_still_ok(self): + # issue#12: K=1 且 B>=128 仍走 UB 乒乓 (原行为不变) + r = self.router.route(mkcase(128, 256, 256, 1)) + self.assertEqual(r["branch"], "特殊分支") + self.assertIn("乒乓", r["plan"].l1_form) + self.assertIsNotNone(r["timing"]) + + def test_issue13_merge_b0_l0ab_capped(self): + # issue#13: MergeBatch 瘦长 case 的 b0 受 L0A/L0B 容量约束 (B=811 M=33 N=1 fp32) + from bmm_theory.constraints import check_plan_constraints + case = mkcase(811, 33, 1, 2459, dtype_a="fp32", dtype_b="fp32", dtype_c="fp32") + r = self.router.route(case) + self.assertEqual(r["branch"], "MergeBatch") + p = r["plan"] + self.assertLessEqual(p.base_m * p.base_k * 4 * 2, 64 * 1024) # L0A 容量内 + self.assertLessEqual(p.base_n * p.base_k * 4 * 2, 64 * 1024) # L0B 容量内 + self.assertEqual(check_plan_constraints(case, p), []) + + def test_issue13_router_fallback_when_winner_infeasible(self): + # issue#13: 仲裁胜出的 MergeBatch 自检违规时, 回退到可行候选 IterBatch + from bmm_theory.constraints import check_plan_constraints + case = mkcase(256, 1, 256, 4096, dtype_a="int8", dtype_b="int8") # 原 0.2% 违规样例 + r = self.router.route(case) + self.assertEqual(r["branch"], "IterBatch") # 回退 + self.assertIn("自检违规", r["arbitration"]) + self.assertIn("回退", r["arbitration"]) + self.assertEqual(check_plan_constraints(case, r["plan"]), []) + + def test_issue15_input_validation(self): + # issue#15: 非法维度/负值必须抛错, 不再静默产出伪方案 + for kw in (dict(m=0), dict(m=-5), dict(n=0), dict(k=-1), + dict(batch_a=0), dict(batch_b=-3)): + with self.assertRaises(ValueError, msg=str(kw)): + BmmCase(case_id="bad", **kw) + with self.assertRaises(ValueError): + BmmCase(case_id="bad", m=64, n=64, k=1, dtype_a="xxx") + + if __name__ == "__main__": unittest.main()