PLAN-0001:DSA compute 补全 实现计划
基于:G5-DSA算子建模设计规格(Accepted v1.0.0)。前置:matmul 建模、softmax 向量算子(Vec 引擎 + vec_dep 串行依赖,已实现)。 日期:2026-06-22 状态:Done
目标
补全 G5 漏掉的 DSA compute 缺失项——lightning indexer 全 N 评分(主导)+ topk 选择 + 稀疏 KV gather + DSA softmax,使 DSA 算子分解口径完整、长上下文下 indexer 主导项不再被漏算。
Dependencies
- softmax 已实现的可复用件:Rust
tier3/vector.rs(向量吞吐)、VectorOpType(当前仅 Softmax)、VectorCommand、跨语言传递链、core_subsyson_vec_finish、DepEngine::Vec+ DMAvec_depgate、emitter_emit_fa2的 softmax 发射 + 串行依赖。 - 现成件:
SDMACommandType::Gather(types.rs:44)已存在;sdma.rscalc_sdma_latency按 data_bytes 算(无 gather 专门处理,契合 spec「按 bytes/带宽、无随机访问惩罚」)。fa2 分支(instruction_emitter.py ~line 160)已有 QK^T + softmax + PV 串行。 - DSA 稀疏注意力可映射 fa2 op:B=B·n_index_heads、QS=S、KS=topk、QD=q_dim、VD=v_dim——复用 fa2 路径得 softmax。
- Rust 改后
maturin build --release+ 覆盖根目录g5_rspyd(记忆 project_g5_pyd_shadowing)。
文件变更概览
| 文件 | 改动 |
|---|---|
perfmodel/workload/layers/dsa.py | _build_ops 重写(5→~8 op):补 indexer query-proj + indexer scoring(KS=全 N)+ ReLU/wsum 向量 + topk-select 向量 + gather + 稀疏注意力改 fa2 op(KS=topk,复用 base.py _fa2_op helper,同 MLA);build_intra_graph 重写(现硬编 len(ops)<5 + 解包 5 op,必随新 op 列表改,参照 mla.py 模式);compute_flops/compute_memory 同步含 indexer 评分;清理现有 _config.get(k, default) 默认值改 raise(config-loading 规则) |
perfmodel/evaluation/g5/src/types.rs | VectorOpType 加 ReluWeightedSum、TopkSelect;DMACommand 加 sdma_dep 字段(gate fa2 等 gather);SDMACommand 加 bandwidth_domain 字段(分域) |
perfmodel/evaluation/g5/src/tier3/vector.rs | calc_vector_latency 按 op_type 分支选公式/op_count 步表/访存口径(非仅加变体):ReLU/wsum 向量吞吐(仿 softmax 逐元素+归约)、topk-select 选择成本(∝N 全 N 扫描、厂商中立,不复用 HAU) |
perfmodel/evaluation/g5/src/tier3/core_subsys.rs | try_issue_dma 加 sdma_dep gate(if cmd.sdma_dep > self.sdma_sync_id break,仿 vec_dep);vector_op_name 加新变体;get_sync_id 已含 Vec 无需改 |
perfmodel/evaluation/g5/src/tier3/sdma.rs | calc_sdma_latency 按 bandwidth_domain 选带宽(prefill 片内 / decode HBM),不再单一 sdma 引擎 |
perfmodel/evaluation/g5/src/input_parse.rs | parse_vector_op_type 加新变体字符串 |
perfmodel/evaluation/g5/src/input/parse_commands.rs | parse_dma_command 加 sdma_dep、parse_sdma_command 加 bandwidth_domain extract(跨语言传递链) |
perfmodel/mapping/g5/program.py | VectorOpType 加新变体;DMACommand 加 sdma_dep;SDMACommand 加 bandwidth_domain |
perfmodel/mapping/g5/instruction_emitter.py | DSA 发射链:indexer matmul + ReLU/wsum/topk VectorCommand + gather SDMA + fa2;跨引擎串行依赖边(vec→sdma 用 vec_dep、sdma→fa2 用新 sdma_dep);fa2 KV 访存边从 gather buffer 读(不双算,口径定在 §隐式假设决议) |
configs/chips/SG2262.yaml + _template.yaml | topk-select / gather 带宽域参数 + 同步模板 |
tests/evaluation/g5/test_dsa_modeling.py(新增) | 据本 plan 测试用例清单的 test cases |
隐式假设决议(执行前定死,不留运行时裁)
- fa2 KV 不双算改哪处口径:fa2 访存边在 workload 层
fa2.py compute_memory_access(算 Q/K/V bytes);G5 实跑是 emitter 把 fa2 拆 matmul 后的 DMA 搬运量。定:gather 负责把 topk KV 搬进连续 buffer(SDMA bytes=topk KV),fa2 的 K/V 操作数视为已在 buffer(near-LMEM)、其 matmul 访存边按 buffer 读计,不再独立计 KV cache→片上的搬运。即"KV cache→buffer"归 gather、"buffer→PE"归 fa2 matmul 访存边,两段不重叠。 - ReLU/wsum 收缩维用 VectorCommand 哪个字段:ReLU 逐元素(无收缩),per-head 加权和跨 n_index_heads 归约。VectorCommand 字段 b/q/k:b=B·n_index_heads(含头维)、q=S、k=N(全 N 评分行)。per-head 归约并入 b 维的吞吐量,不新增字段。Task 2 验证 b/q/k 够表达,不够则停下报告。
Rules Compliance
- config 禁默认值:新增 VectorOpType / gather / topk 参数缺字段 raise 带字段名,不兜底;且清理 dsa.py 现有
_config.get(k, default)默认值(重写_build_ops/compute_flops时触碰这些行,按规则改 raise,Task 1b)。 - no-backward-compat:DSA 分解直接改(不留"只发 5 matmul"旧分支 / "不建 softmax"分支)。
- naming(_gb_per_s):gather 带宽域字段用
_gb_per_s。 - sync-templates:改 SG2262.yaml 结构同步
_template.yaml。 - windows-encoding:Rust/Python 输出无特殊 Unicode([OK]/[FAIL])。
- 不碰
DepEngine::Cdma=>0:A1/A2 边界。串行依赖用DepEngine::Vec/ 等价,不碰 Cdma。 - 不复用 HAU 排序公式:topk-select 走 Vec 厂商中立成本。
- strict 无容差:结构/形态/wall-clock 断言严格。
- Rust 改后 maturin 重建 + 覆盖根目录 pyd。
无 Complexity Tracking 偏离。
实现步骤
Task 1a [Sequential,基础] — DSA 稀疏注意力迁 fa2(最小可达验证)
先只把 DSA 现有 attn_score + attn_out 两 matmul 换成一个 fa2 op,复用 MLA 成熟路径,独立验证可达(fa2 映射是前置高风险点,先隔离验证)。
dsa.py_build_ops:attn_score + attn_out →base.py_fa2_op(B=B·n_index_heads、QS=S、KS=effective_kv=topk、QD=q_dim、VD=v_dim)。注意 G/M/K/N → B/QS/KS/QD/VD 的 key 名转换。build_intra_graph随之改(op 数变、解包改)。compute_flops/compute_memory暂不变(仍 topk 口径,indexer 留 1b)。
Acceptance:DSA prefill e2e 走 fa2 路径、含非零 softmax 分量;现有 DSA 测试不破(pytest)。
Task 1b [Sequential,依赖 1a] — 补 indexer 评分 + 选择 + gather 进分解
dsa.py _build_ops / build_intra_graph / compute_flops / compute_memory 补完整链。
- indexer query 投影(小项):matmul op(V4 低秩=降维+上投影,或 V3.2 直接),归投影项。
- indexer 全 N 评分(主导):matmul op,shape=[S, d_index]@[d_index, N=全 kv_seq_len](n_index_heads 批量、MQA 共享 key、FP8)。收缩维=全 N,区别于 fa2 的 KS=topk。
- ReLU + per-head 加权和:VectorCommand(ReluWeightedSum),字段口径见 §隐式假设决议。
- topk-select:VectorCommand(TopkSelect),输入 N 个 score。
- gather:SDMA Gather 命令,bytes=topk KV。
build_intra_graph随 ~8 op 重写解包与边;compute_flops加 indexer 评分(∝N²·n_index_heads·d_index);compute_memory含 gather。- 清理
_config.get(k, default)默认值改 raise(config-loading)。
Acceptance:构造 DSA 层验分解含 indexer 全 N 评分(收缩维=N)+ ReLU/wsum + topk + gather + fa2,缺一即红;indexer 评分收缩维=N vs fa2 KS=topk 不重叠;compute_flops 含 indexer 评分项;缺配置字段 raise(pytest workload)。
Task 2 [Sequential,依赖 1b] — Rust 向量算子扩展(op_type 分支 + 全枚举链)
types.rs + vector.rs + 三处枚举同步 + 传递链。
VectorOpType(types.rs)加ReluWeightedSum、TopkSelect;同步三处枚举:Pythonprogram.pyVectorOpType、input_parse.rsparse_vector_op_type、core_subsys.rsvector_op_name(softmax 当初漏 G1 的同款链,逐处列防漏)。vector.rscalc_vector_latency按 op_type 分支(现 softmax_theo/memory_edge/combine 硬编 softmax 语义):ReluWeightedSum 走向量吞吐(逐元素+per-head 归约)、TopkSelect 走厂商中立选择成本 ∝N 全 N 扫描(随 N 线性、非随 topk),不复用 HAU(hau.cc cal_cycle 是 stub)。- 参数缺字段 raise。
Acceptance:cargo test——两新 op_type 的 calc_vector_latency 按各自公式产出(TopkSelect 成本随 N 线性、固定 topk 不变);缺字段 raise;不引用 HAU;softmax 既有单测不破。
Task 3 [Sequential,依赖 1b] — gather SDMA 带宽域字段(从零加)+ 不双算
SDMACommand 无 bandwidth_domain 字段、calc_sdma_latency 单一引擎——从零加分域。
- SDMACommand 加
bandwidth_domain字段:types.rs +program.pySDMACommand +parse_commands.rsparse_sdma_commandextract(跨语言链)。 sdma.rscalc_sdma_latency按bandwidth_domain选带宽(prefill 片内段 / decode HBM 段),不再单一 sdma 引擎;带宽字段_gb_per_s。- 不双算:按 §隐式假设决议——gather 搬 KV cache→buffer(SDMA bytes=topk KV),fa2 K/V 访存边按 buffer 读计,两段不重叠。
- 新参数(gather 带宽域)下沉 YAML + 同步
_template。
Acceptance:gather SDMA bytes=topk KV、bandwidth_domain 随 prefill/decode 变(prefill 片内、decode HBM);calc_sdma_latency 按域选带宽;fa2 KV 边与 gather 覆盖的 topk KV 不重复计(cargo test + 比对覆盖)。
Task 4 [Sequential,依赖 1b] — sdma→fa2 跨引擎 gate(BLOCKING 缺口,独立补)
串行链 gather(sdma)→fa2(tiu/dma) 现有机制无法表达(DMA 只能 gate tiu_sync_id/vec_sync_id,TIU 只能 gate tdma_sync_id,无谁等 sdma_sync_id)。从零加 sdma_dep gate(仿 softmax 的 vec_dep 整链)。
- DMACommand 加
sdma_dep字段:types.rs +program.pyDMACommand +parse_commands.rsparse_dma_commandextract。 core_subsys.rstry_issue_dma加 gate:if cmd.sdma_dep > self.sdma_sync_id { break }(仿 vec_dep)。- emitter
_emit_matmul_double_buffered加initial_sdma_dep透传到 fa2 的 QK^T prologue DMA。 - 不碰 DepEngine::Cdma=>0。
Acceptance:cargo test——含 sdma→fa2 的 CoreProgram 跑通,fa2 prologue DMA 等 gather 完成(fa2.start ≥ gather.end),无悬挂事件 / 死锁;默认 sdma_dep=0 不阻塞非依赖 DMA。
Task 5 [Sequential,依赖 1b,2,3,4] — emitter DSA 发射链 + 重建
instruction_emitter.py:DSA 算子按链发射,跨引擎串行依赖边连对。
- 发射顺序:indexer 投影 matmul → indexer 评分 matmul → ReLU/wsum VectorCommand → topk-select VectorCommand → gather SDMA → fa2(稀疏注意力 + softmax)。
- 串行依赖边逐跳连:matmul→vec(vec dep_engine=tiu)、vec→vec(vec_busy 单槽)、vec→sdma(sdma vec_dep)、sdma→fa2(fa2 prologue DMA 的 sdma_dep,Task 4 件)。
- maturin build --release + 覆盖根目录 pyd。
Acceptance:DSA prefill 单芯片 e2e——EngineResult 含 indexer 评分(非零、随 S 增)、ReLU/wsum、topk、gather、softmax 各分量非零;wall-clock 后继 start ≥ 前驱 end(评分→选择→gather→attn 串行不掩盖)。
Task 6 [P,依赖 spec,可与 Task 1a 起并行起草] — 测试用例清单(写进本 plan 小节,先于 test 代码)
填下方「测试用例清单」小节:每 case 输入 / 预期 / spec 验收点 / 断言性质 / 落点。覆盖 spec 全部验收行(含 unvalidated 门控)。
Acceptance:清单覆盖 spec 验收标准全部行;每 case 标清断言性质与落点。
Task 7 [Sequential,依赖 6 + Task 5] — test case 代码
tests/evaluation/g5/test_dsa_modeling.py:据清单写 test case。
Acceptance:所有 case 通过;变异有效(删 indexer 评分发射 / 串行依赖边 → 对应 case 变红)。
Task 8 [Sequential,依赖 7] — 回归
- 现有 G5 测试(cargo test + pytest tests/evaluation/g5/ 当前 80 passed)不破。
- matmul / softmax / 通信侧 / A1 桥不受影响。
Acceptance:cargo test 全绿 + pytest tests/evaluation/g5/ 全绿。
验证计划
- 单元:Rust 向量算子(Task 2 cargo test)、gather 分域(Task 3)、sdma_dep gate(Task 4)。
- 集成:DSA 端到端含全部缺失项 + 串行不掩盖(Task 5)。
- 结构/趋势:indexer 评分收缩维=N、主导性随 S 单调增(趋势非绝对倍数);不双算(评分 vs fa2、gather vs fa2 KV)。
- 回归:现有 G5 全量不破(Task 8)。
- Rust 改后 maturin 重建 + 覆盖根目录 pyd。
测试用例清单(Task 6 产出,Task 7 据此写代码)
| # | case | 输入 | 预期 | spec 验收点 | 断言性质 | 落点 |
|---|---|---|---|---|---|---|
| D1 | indexer 评分补入 | 构造 DSA 层 | 分解含 indexer 全 N 评分(收缩维=N、非零) | indexer 评分补入 | 结构/严格 | pytest workload |
| D2 | indexer 主导性趋势 | 扫 S(128K→1M),固定 topk | indexer/稀疏注意力 算力比随 S 单调增 | indexer 主导性(趋势) | 行为(单调) | pytest |
| D3 | 评分不双算 | DSA 分解 | indexer 评分收缩维=N vs attn(fa2) KS=topk,不重叠 | 评分不双算 | 结构 | pytest workload |
| D4 | DSA 含 softmax | DSA prefill e2e | attn 分量含非零 softmax、串行计入 | DSA 含 softmax | 行为 | pytest e2e |
| D5 | gather 不双算 | DSA 分解 + e2e | gather 覆盖 topk KV、fa2 KV 边从 buffer 读,不重复计 | gather 不双算 | 结构 | pytest |
| D6 | gather 分域 | prefill vs decode | gather 带域:prefill 片内 / decode HBM | gather 分域 | 行为 | pytest / cargo |
| D7 | topk 厂商中立 + 全 N 视野 | 改参数 + 扫 N | 选择成本随 N 线性(非随 topk)、无 HAU 依赖 | topk 厂商中立 + 全 N 视野 | 行为 | cargo / pytest |
| D8 | 串行链不掩盖 | DSA prefill e2e | 后继 op_start ≥ 前驱 op_end(评分→选择→gather→attn) | 串行链不掩盖 | 行为(wall-clock) | pytest e2e |
| D9 | 门控继承 | unvalidated 置位 + DSA 绝对查询 | 返回相对、不返回绝对(复用既有门控) | 门控 unvalidated | 行为 | 继承既有 test_slo_gate |
| D10 | 变异有效性 | 删 indexer 评分发射 / sdma_dep 串行边 | D1/D8 对应 case 变红 | —(测试有效性) | 手动变异 | Task 7 |
| D11 | 回归 | 全量 | 现有 80 G5 测试不破 | 回归 | 严格(继承) | cargo + pytest |
风险与回退
| 风险 | 缓解 |
|---|---|
| DSA 迁 fa2 工作量级超预期 | Task 1a 独立隔离验证 fa2 映射(复用 MLA 成熟 _fa2_op);不能则停下报告回 spec,不与新算子缠绕 |
| gather 不双算需改 fa2 KV 访存边口径有歧义 | §隐式假设决议已定死:gather 归 KV cache→buffer、fa2 matmul 边归 buffer→PE,两段不重叠(Task 3);不留运行时裁 |
| sdma→fa2 串行 gate 现有机制无法表达 | Task 4 独立从零加 sdma_dep gate(仿 vec_dep 整链);Task 5 串行链用它连 sdma→fa2;acceptance 验 wall-clock 后继 ≥ 前驱(D8) |
| topk-select 走 Vec 失真(硬件是排序引擎) | spec 已定小项、厂商中立 ∝N 成本;小项错也只在 wall-clock 串行时小幅显现 |
| indexer 评分补全使 DSA 显得和稠密一样贵 | spec 已论证:indexer 真是 O(N²),如实显示是正确,非建模错误 |
| 新增 VectorOpType 破坏 softmax 既有路径 | Task 2 只加变体不改 Softmax 分支;Task 7 回归验 softmax 测试不破 |