跳到主要内容

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_subsys on_vec_finishDepEngine::Vec + DMA vec_dep gate、emitter _emit_fa2 的 softmax 发射 + 串行依赖。
  • 现成件:SDMACommandType::Gather(types.rs:44)已存在;sdma.rs calc_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_rs pyd(记忆 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.rsVectorOpTypeReluWeightedSumTopkSelectDMACommandsdma_dep 字段(gate fa2 等 gather);SDMACommandbandwidth_domain 字段(分域)
perfmodel/evaluation/g5/src/tier3/vector.rscalc_vector_latency 按 op_type 分支选公式/op_count 步表/访存口径(非仅加变体):ReLU/wsum 向量吞吐(仿 softmax 逐元素+归约)、topk-select 选择成本(∝N 全 N 扫描、厂商中立,不复用 HAU)
perfmodel/evaluation/g5/src/tier3/core_subsys.rstry_issue_dmasdma_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.rscalc_sdma_latencybandwidth_domain 选带宽(prefill 片内 / decode HBM),不再单一 sdma 引擎
perfmodel/evaluation/g5/src/input_parse.rsparse_vector_op_type 加新变体字符串
perfmodel/evaluation/g5/src/input/parse_commands.rsparse_dma_commandsdma_depparse_sdma_commandbandwidth_domain extract(跨语言传递链)
perfmodel/mapping/g5/program.pyVectorOpType 加新变体;DMACommandsdma_depSDMACommandbandwidth_domain
perfmodel/mapping/g5/instruction_emitter.pyDSA 发射链: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.yamltopk-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)加 ReluWeightedSumTopkSelect同步三处枚举:Python program.py VectorOpType、input_parse.rs parse_vector_op_typecore_subsys.rs vector_op_name(softmax 当初漏 G1 的同款链,逐处列防漏)。
  • vector.rs calc_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 带宽域字段(从零加)+ 不双算

SDMACommandbandwidth_domain 字段、calc_sdma_latency 单一引擎——从零加分域。

  • SDMACommand 加 bandwidth_domain 字段:types.rs + program.py SDMACommand + parse_commands.rs parse_sdma_command extract(跨语言链)。
  • sdma.rs calc_sdma_latencybandwidth_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.py DMACommand + parse_commands.rs parse_dma_command extract。
  • core_subsys.rs try_issue_dma 加 gate:if cmd.sdma_dep > self.sdma_sync_id { break }(仿 vec_dep)。
  • emitter _emit_matmul_double_bufferedinitial_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 桥不受影响。

Acceptancecargo 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 验收点断言性质落点
D1indexer 评分补入构造 DSA 层分解含 indexer 全 N 评分(收缩维=N、非零)indexer 评分补入结构/严格pytest workload
D2indexer 主导性趋势扫 S(128K→1M),固定 topkindexer/稀疏注意力 算力比随 S 单调增indexer 主导性(趋势)行为(单调)pytest
D3评分不双算DSA 分解indexer 评分收缩维=N vs attn(fa2) KS=topk,不重叠评分不双算结构pytest workload
D4DSA 含 softmaxDSA prefill e2eattn 分量含非零 softmax、串行计入DSA 含 softmax行为pytest e2e
D5gather 不双算DSA 分解 + e2egather 覆盖 topk KV、fa2 KV 边从 buffer 读,不重复计gather 不双算结构pytest
D6gather 分域prefill vs decodegather 带域:prefill 片内 / decode HBMgather 分域行为pytest / cargo
D7topk 厂商中立 + 全 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 测试不破