ISSUE-044: G5 建模与测试 Code Audit — Findings 汇总
发现日期:2026-06-10
状态:部分已修复 (2026-06-10 plan 执行完成:护栏 3 项 + P0-1/2/3/4 + 存量 4 bug — tcredit 零字节帧 credit 泄漏 / p2p Send retire 错芯片 / switch 丢包 credit 对账 / psn_gaps 净计数;剩余 P0-5/6 + P1/P2/P3 见 plan 阶段外清单)
类型:实现 bug + 建模误差 + 测试缺口 混合
影响范围:G5 仿真引擎 (perfmodel/evaluation/g5/)。collective 展开层 DBT / hierarchical / 2-port 三条路径在仿真语义下产出错误结果;测试体系对这些路径覆盖为零,golden/MR 仅跑 pairwise alltoall。基建层 (守恒插桩 / 事件核 / CBFC 对账) 质量高,不受影响。
审查方法
对 G5 全量代码 (7 个 Python 胶水文件 + 93 个 Rust 文件,~25k 行) 与 ~448 个 Rust 测试 + Python 测试做 5 维独立 audit (Correctness / Structure / Rules / Efficiency / Test-effectiveness)。3 个 P0 经主对话抽查复核 (读源码确认行号与逻辑)。
问题现象 (按严重度汇总)
P0 正确性 (会产出错误结果,必修)
| ID | File:Line | Issue | 后果 |
|---|---|---|---|
| P0-1 | collective/tree_allreduce.rs:24 vs :118 | DBT broadcast 方向倒置:edges 存 (child, parent), broadcast 循环按 &(parent, child) 解构,emit 出来仍是 child→parent | root 永不下发,依赖结构全错;测试只数 Transfer 总数 (=12) 抓不到 |
| P0-2 | collective/tree_allreduce.rs:55-102 | last_msg_id 消费后不清除,同 chip 第二条 MsgWait 等已被消费的 msg_id (msg_central 是消费语义) | DBT 进仿真即 stall;守恒护栏无"CDMA cmd 未 retire"检查 → latency 静默截断偏小 |
| P0-3 | collective/hierarchical.rs:149-160 | 维度间依赖只挂 cmds[0] 且 dep 是 thread 级,跨维 thread 不一致 → 永不满足或错误并行 | 分层 collective (BlueConnect 路径) 整条不可信 |
| P0-4 | collective/expand.rs:137-141 + top/multi_chip/setup.rs:226-231 | 2-port × 多 channel 映射 unit 0..2C-1 越界,加载层 if unit_idx < units.len() 静默丢命令 | 半数 channel 凭空消失,字节守恒破坏 + 静默截断。这是 ISSUE-025 搁置的 2-port 标度问题的根因之一 |
| P0-5 | comm_result_builder.py:83 | busbw 分子用 msg_size_bytes 漏乘 spec.repeat,而 latency 覆盖 repeat 次传输 | repeat>1 时 busbw 低估 repeat 倍;busbw 是 sweep 排序 score (engine_adapter.py) |
| P0-6 | lib.rs:48-103 | cancel_check 仅仿真启动前调一次,cancel_flag 是函数内局部 Arc,启动后无人能置位,主循环每 1000 事件的轮询是死代码 | 分钟级多芯片仿真无法中途 kill,与 CLAUDE.md "取消靠 AtomicBool 轮询" 描述不符 |
P1 结构 / 正确性风险
| ID | File:Line | Issue |
|---|---|---|
| P1-1 | rc_link_tx.rs:415 + event_handlers/paxi.rs:329 | NAK 处理先 on_ack, process_ack 无条件 retry_counter.remove,即使释放 0 slot;持续丢同一 PSN 时 counter 反复清零 → max_retry=15 永不命中,Go-Back-N livelock, liveness 探测也不报警 (每次重传刷新 last_progress)。与 ISSUE-041 不同:041 修 timer 太紧致 spurious 重传,本条修 counter 清零致 max_retry 失效 |
| P1-2 | event_handlers/shared.rs:47-56 | ACK/CNP 反向路由失败时静默 fallback 零延迟立即送达 → 时序系统性偏快,守恒抓不到 (数据照常流动) |
| P1-3 | switch.rs:247-298 | iSLIP grant 用 HashMap RandomState 迭代 → 仿真不可复现;priority=3 (tcredit) 不保证优先于 priority=2 数据 |
| P1-4 | collective/helpers.rs:189 + expand.rs:56,82 | 1-port ring msg_id 段隔离仅 step<32 成立,C>4 且 N≥17 跨 channel 计数污染;2-port 断言 <32 是对的,1-port 漏了 |
| P1-5 | collective/p2p.rs:9 | 模块级 static THREAD_COUNTER: AtomicU32 分配 thread,不复位;PyO3 常驻进程下同 program 连续两跑结果漂移;%8 硬编码无视 threads_per_cdma |
| P1-6 | collective/tree_allreduce.rs:45,105 | DBT 两棵树串行 (共享 last_cmd_id + 全 thread 0) + parent 只 MsgWait 最后一个 child → DBT 并行收益未建模,延迟 ≈2× 理论值 |
| P1-7 | top/multi_chip.rs:72-79 | 空 chips 守卫在 .expect("...paxi...") 之后,永不可达;空输入先 panic 跨 FFI |
| P1-8 | cdma/callbacks.rs:22-30 | 完成回调硬编码 tx_threads, Rx group 指令 pending_count 永不递减;hierarchical 用例触发 Rx thread pending 泄漏 → 永久 FenceWait |
| P1-9 | sim_engine.py:55 / comm_primitive_pipeline.py / pipeline.py:23 | sim_engine 路由空路径静默编造直连;pipeline.py 收 network_graph/routing_strategy 参数但从不使用,多芯片退化单芯片无报错 |
P2 规范合规 (项目铁律)
| ID | File:Line | Issue |
|---|---|---|
| P2-1 | input/parse_topology.rs:44-125 | 死代码全链路 (旧 interconnect 格式),携带"缺字段 eprintln WARN + 空 map"违例 (config-loading 铁律) + 旧格式残留 (no-backward-compat);无生产调用方,应整体删除 |
| P2-2 | comm_primitive_pipeline.py:59 / comm_result_builder.py:78 | dma_engines.get("cdma")→端口数兜底 1;未知 primitive 兜底 1.0 — 违反禁默认值铁律 |
| P2-3 | rc_link_dcqcn.rs:22 | timer_interval_ns: 3_000.0 vs 注释 "55us",差 18× (DCQCN 标准 55μs) |
| P2-4 | input/parse_chip.rs:109 / parse_topology.rs:64 | get_item 任何错误当"引擎不存在"; .and_then(extract().ok()) 类型错静默吞 None — fail-loud 缺失 |
| P2-5 | common/trace.rs:53 + lib.rs:81 | 未知 trace category 字符串 filter_map 静默丢弃 → typo 得空 trace 无报错 |
| P2-6 | comm_result_builder.py:43 vs comm_primitive_pipeline.py:71 | 同一 total_sim_time_ns 缺失,一处 raise 一处兜底 agg.total_time*1e6,行为不一致 |
| P2-7 | tests/evaluation/g5/test_adapter.py:31 | chip fixture 读真实 SG2262.yaml,应复用 conftest 的内存 chip_spec (单测不读真实 YAML 约定) |
P3 风格 / 效率 / 死代码
| ID | File:Line | Issue |
|---|---|---|
| P3-1 | cdma/tests.rs:1699 | AI 自言自语死注释 "(我的 mask 设错了,让我重新算...wait)",且算式本身写错 |
| P3-2 | rc_link_tx.rs:383 | process_ack 每次扫全 512 slots + retain(contains) O(slots×pending), ACK 最热路径 |
| P3-3 | sim_kernel.rs:152 | cancel_timer 对已 fire timer 的 tid 永留 cancelled HashSet,长仿真无界增长 |
| P3-4 | expand.rs:22 / 各 emit 点 | source_op_id: String 每条 cmd 克隆 (ring N=64 C=8 上万次),可改 Arc<str> |
| P3-5 | c2c_link.rs vs c2c_network.rs PhyLink | 两套几乎相同物理链路实现,易漂移 |
| P3-6 | forwarding/ecmp_hash.rs:47 | ECMP 用恒等 flow_id % K 无 hash,易系统倾斜;flow_cache 无淘汰长仿真内存涨 |
| P3-7 | build_g5rs.py:85 | 非 Windows 只找 .so, macOS .dylib 必失败;产物复制到根目录 shadow maturin 装的版本 |
| P3-8 | adapter.py:80-104 | DMA engine 的 duration 不进任何 bucket, total_memory_time 永远 0, memory-bound 算子瓶颈分析失真 |
测试有效性 (核心问题)
| ID | File:Line | Issue | 关联 |
|---|---|---|---|
| T-1 | golden 16 cell (driver.rs:210) | 全部是 alltoall + pairwise; routing 维度纯标签 (全跑静态路由);n_ports 不改 unit 数。4 个 P0 全部在零覆盖路径上,这是它们能存活的原因 | — |
| T-2 | top/multi_chip/tests.rs 全文件 | 21 个集成测试 19 个未调用 assert_conservation,断言多为 sim_time>0 + 5× 宽界。这是 MEMORY "G5 存活性验收缺陷" pending 项的主体,helper 已存在纯接线 | MEMORY g5_test_hardening |
| T-3 | tests/ 全目录 | 无 G5×Math 差分校验,两路径从未互比;golden 只防"变"不防"错" | ISSUE-016 |
| T-4 | mr_tests.rs:100 | MR3 比较两次完全相同的仿真 (n_ports 不改 unit 数),恒等通过却未声明 LIMITATION | — |
| T-5 | golden/update_golden | 确定性仿真配 1% 容差 + update 即重基线 → 容差棘轮,系统性慢漂移不可见 (与 ISSUE-041 lesson 一致) | ISSUE-041 |
| T-6 | collective *.rs 89 测试 | 全停在命令生成计数层 (cmd 数/msg_id/依赖),无时序对照解析公式;删调度串行化约束命令结构不变,测试全绿 | — |
交叉引用 (与现有 issue 关系)
| 现有 issue | 关系 |
|---|---|
| ISSUE-025 (测试覆盖缺口) | ISSUE-025 记载的两个 2-port ignored 测试现已激活 (tests.rs:299/317) 但 fixture total_cdma_units=1 不经过 replicate_channels,探测不到 P0-4。P0-4 验收需新增 C≥2 × 2-port 测试 (见 plan Task 7) |
| ISSUE-041 (retry_timer 太紧) | P1-1 是不同 bug: 041 修 timer 时长致 spurious 重传;P1-1 修 retry_counter 无条件清零致 max_retry 永不命中 livelock。两者都在 RC Link 重传路径 |
| ISSUE-016 (AG/RS G5-Math 差分) | T-3 (无 G5×Math 差分校验) 是 016 的系统化延伸 |
| MEMORY: G5 测试加固 | T-2 (守恒断言接线) + T-3 (差分) 即该 pending 项的两个落地方向 |
修复优先级 (建议顺序)
阶段 1 — 先堵静默截断 (改护栏,不改算法;让坏路径从"错数据"变"显式红")
collect_results增加"所有 CDMA sendq/rcvq 排空"守恒线,纳入 CONSERVATION_KEYS (堵 P0-2/3/4 的静默截断)setup.rs:226unit 越界if unit_idx < units.len()改panic!(带 chip/thread/units.len)event_handlers/shared.rs:47ACK 路由失败计数到独立 stat 纳入守恒,不静默零延迟top/multi_chip/tests.rs19 个集成测试结尾统一接assert_conservation(helper 已存在)
阶段 2 — 修 6 个 P0 (此时有失败基线兜底)
- P0-1 + P0-2: tree_allreduce 方向修正 + msg_id 消费后清除 (并补 direction 断言测试)
- P0-3: hierarchical 维度间用 chip 级同步原语
- P0-4: expand_one 容量除以 units_per_port_mode (新增 total_cdma_units≥2 × 2-port 仿真测试验收;tests.rs:299/317 为 C=1 路径不覆盖本修复)
- P0-5: busbw 分子乘 repeat (+ repeat>1 回归测试)
- P0-6: cancel 机制改为暴露 AtomicBool 句柄给 Python 侧持有,或 detach 闭包内周期 try_attach 回调
阶段 3 — P2 规范 + 正确性对照测试
- P2-1 删 parse_topology 死代码全链路;P2-2 去默认值兜底;P2-3 对齐 DCQCN timer
- collective × 解析公式时序对照测试 (ring AR=2(N-1) 步精确值); golden 矩阵扩到 allreduce/HD/DBT,容差降 0
- G5×Math 差分测试 (承接 ISSUE-016)
阶段 4 — 结构 / 性能 (非阻塞)
- P1-1/2/3/5 复现确认后修;P3 系列 (ACK 索引化 / c2c 单实现 / Arc
/ ECMP hash)
验证
- 阶段 1 完成判据:跑现有 DBT/hierarchical/2-port 用例应变红 (守恒线触发),证明护栏有效
- 阶段 2 每个 P0 修复后,对应路径守恒线回绿 + 新增 direction/timing 断言通过
- 新增 C≥2 × 2-port 仿真测试通过 (2-port 快于 1-port + 守恒全绿);tests.rs:299/317 保持现状,不作为 P0-4 验收
- 全量
cargo test --release+pytest tests/evaluation/g5/0 失败
遗留问题
- P1-1 livelock / P1-8 Rx pending 泄漏为静态推导结论,未跑端到端复现 (当前 collective 路径全 Tx group, P1-8 未触发)
- F9 (2-port
ceil(N/2)步数模型 vs 标准双向 ring 偏差 33%) 是建模选型问题,需对 G5-CDMA spec 裁定后再定修复方向 - 完整 5 维 audit 原始报告 (含每条 Why-it-matters 详述) 在本会话产出,未独立成文