跳到主要内容

ISSUE-034 — G5 alltoallv 仿真帧静默丢失 + 提前终止 (busbw 超物理上限的真因)

字段
日期2026-06-04
状态已修复 (per-LG 容量取货 + 守恒护栏 + 守恒/单测;全量 v5 重跑 0 超限;code-review APPROVED)
类型仿真正确性 bug — segment 在 CDMA→PAXI→LG 流转中静默丢失,导致仿真在数据传完前终止
影响范围G5 feed_rc_link / take_segments / dispatch_segments 全局 vs per-LG 容量口径错配;topo-routing-comm-eval 全部数据集 (v2/v3/v4) 作废,所有 latency/busbw 基于残缺传输
关联ISSUE-031 (push-driven 重构引入本回归);ISSUE-033 (busbw 超 400 是本 issue 的症状,per-LG SerDes cap 物理正确予以保留)

结论速览

根因feed_rc_link全局 slot 容量 (8 LG free_slot 之和) 决定 take_segments 取多少 segment; segment 按 hash_lg 投到特定 LG;该 LG slot 满时 submit_frame 返回 false + diag_slot_full++,但 dispatch_segments 忽略返回值 → segment 既出队 (seg_total--) 又没进 LG → 永久丢失 → 丢失帧不再产生事件 → 事件队列提前空 → 仿真提前终止 → total_time 偏小 → busbw = C.sum/(N×total_time) 虚高破物理上限 400。

铁证diag_slot_full = 70339 与守恒护栏 unsent_frames = 70339 逐一相等 (single-switch S1 ep32 tok256)。

因果链

帧在 CDMA→PAXI→LG 流转中静默丢失 (root cause)
→ 仿真在 45-71% 数据传完时事件队列空、提前终止
→ total_time 系统性偏小
→ busbw = 全量 C.sum / 偏小 total_time > 400 (ISSUE-033 观察到的"症状")

问题现象

topo-routing-comm-eval 数据集 per-chip busbw 超物理上限 400 GB/s (SG2262 8 LG × 50)。v4 (exp38) 全量 2779 cell 中 203 个 bus_bw_gb_per_s > 400, max 439.9。最初定性为"chip 出向超速" (ISSUE-033),实为表象。

调查过程

  • [查 busbw 公式] busbw = total_bytes/(N×total_time) (run_alltoallv.py:539),分子 C.sum() 对角线为 0,公式与口径均正确,非公式 artifact。
  • [Rust 探针] dump 所有 chip 每帧 (chip lg now done wire):单 LG 严格 50.0 GB/s (overlap=0),每 chip 物理出向 ≤396 < 400。物理串行完全正确,per-LG cap (ISSUE-033) 生效,非超速
  • [守恒护栏] multi_chip.rs::collect_resultsincomplete_txns / unsent_frames stat:仿真结束所有 64 chip 各 31 txn 未完成 (acked < total_frames),而 waitack=0 / seg_q=0 / free_slots=4096 (PAXI 全空) → 帧"凭空消失"。
  • [对比 switch 转发] single-switch 所有数据必过 s0,应转发 100%;实测 ep32 仅 45%、ep64 仅 71% (CDMA 发起均 100%) → 数据未传完仿真即结束。busbw 越虚高、转发越不完整 (负相关)
  • [diag 计数器] 聚合 RC_TX diag: slot_full=70339 == unsent_frames=70339 → 丢帧点 = submit_frame slot 满。
  • [查 dispatch_segments] paxi.rs for seg in segments { self.tx_lgs[..].submit_frame(..) } 忽略 bool 返回值 → 丢帧静默。
  • [git 考古] push-driven SegmentDispatch 重构 (ISSUE-031, commit 3899aff) 把 per-LG 容量判断写成全局求和 rc_link_available_capacity

根因分析

口径错配问题
全局容量 vs per-LG 分配feed_rc_link 按"8 LG 总空位"取货,但货按 hash_lg 分到指定 LG;单 LG 装不下 (即使全局够)
dispatch_segments 忽略返回值submit_frame 返回 false (丢帧信号) 被丢弃,segment 既不退回 segment_queue 也不重试

ep=32 流量集中 → hash_lg 分布更偏 → 单 LG 过载更频繁 → 丢更多帧 → 传更少 → busbw 更高,解释 ep32(45%) 比 ep64(71%) 严重。

Spec / 文档依据

来源内容与本 issue
G5-RC-Link 传输层设计规格 line 228Slot 池 per-LG 独立 (每 LG TYPE1_OST)容量判断应 per-LG,实现用了全局求和
同 line 240"Slot 耗尽时新包入 segment_queue 排队,ACK 释放 Slot 后由 feed_rc_link 自动 drain"slot 满留队列不丢帧 — 实现违反 (take 出又丢)

spec 设计正确,实现违反 spec。spec 不改设计,仅澄清 "feed 按 per-LG 容量取货" (line 240,行为描述,不含函数名)。

解决方案

采用feed_rc_link / take_segments 改为按 per-LG slot 容量取货 (回归 spec line 228/240)。

  1. paxi_core.rs (核心):take_segments / drain_pending / submit 签名 slot_budget: usizelg_budgets: &mut [usize]。新增 take_from_txn_queue helper,三类处理:未就绪 (记 earliest_wake + break,依赖 earliest_ready 单调) / 就绪但该 LG 满 (跳过留队列,继续看后续) / 就绪且 LG 有空位 (取走扣预算)。kept VecDeque 保同一 LG 内 seg_idx 递增序 (PSN 连续)。
  2. paxi.rs: feed_rc_link 采样一次 lg_budgets, take 与 drain 共享同一被扣减的 &mut,禁止重新采样 (否则两段重复发放预算 → 超发 → 复发丢帧)。dispatch_segmentssubmit_frame 返回值加 debug_assert!。删死函数 rc_link_available_capacity
  3. multi_chip.rs (护栏,正收益):collect_results 输出 incomplete_txns / unsent_frames stat — release 下兜底,提前终止不再静默。

关键算法不变式earliest_wake 恒 = 所有未就绪 segment 的最小 earliest_ready (只有未就绪段记 wake;满 LG 跳过的是就绪段,earliest_ready≤now 不污染 wake),故不会算晚 wake → 不复现提前终止;同时保留 "未就绪 break" 剪枝,不回退 ISSUE-031 的 O(P²) 优化。

涉及文件:perfmodel/evaluation/g5/src/tier6/paxi_core.rs, tier6/paxi.rs, top/multi_chip.rs(+tests.rs)。Plan: docs/plans/2026-06-04-alltoallv-frame-drop-fix.md

验证 (Acceptance Criteria)

  • 守恒测试 test_alltoall_data_conservation_no_frame_drop (16 chip × 3MB/pair alltoall):修复前红 (incomplete_txns=2, unsent_frames=34),修复后绿 (incomplete_txns==0)。code-review revert 实验复证:改回全局口径即红 (submit_frame slot 满返回 false)。
  • per-LG 单测test_take_segments_per_lg_skip_full (满 LG 跳过 + seg_idx 递增) / test_take_segments_wake_unaffected_by_full_lg_skip (earliest_wake 不被满 LG 跳过干扰,wake=未就绪真实最小值)。
  • cargo test: 364 passed; debug build 守恒测试 debug_assert 不触发 (per-LG 容量与 submit_frame 同口径,ok==true 恒成立)。
  • 全量重跑 v5-framefix (exp39) 2779 cell: busbw>400 = 0, max 339.4 (v4 为 203/2779, max 439.9)。busbw 全面下修因数据真传完、total_time 反映真实传输。
  • code-review (opus, in-flow): APPROVED, 0 P0/P1/P2, 2 P3 (docstring / saturating_sub) 已修。

Lessons Learned / Prevention

  • 测试盲区是 root cause 长期潜伏的原因:修复前 361 测试只断言 sim_time > 0.0 ("仿真跑完且时间为正"),零个数据守恒 / 事务完成断言。提前终止满足 sim_time>0 静默通过。→ 护栏 stat + 守恒测试永久防回归。
  • 诊断信息 ≠ 断言dump_post_sim_diagnostics 早已收集 core_txns 未完成,但只在 G5_DEBUG eprintln,从不 panic,测试看不到。诊断必须升级为可断言的 stat。
  • 生产脚本应 check incomplete_txns==0: validation 脚本每 cell 验收此 stat,残缺数据不再静默进 DB (呼应 validation-data-persistence)。
  • 症状定性要追到物理层:ISSUE-033 把 "busbw 超 400" 定性为"chip 出向超速",探针证明单 LG 物理严格 50、单 chip <400,推翻症状定性,才挖到真因。

遗留问题

  • 结论修正:v5 干净数据下,拓扑相对排序稳定 (single-switch > torus > fat-tree > ring),但路由第一名 dor/dmodk 互换 (v5: dor 292.7 > dmodk 275.2; v4: dmodk 368.2 > dor 363.5,两者接近、丢帧噪声下翻转)。report.md KA1/KA2/KA3 需基于 v5 重写,路由结论改为 "dor 略优于 dmodk"。
  • report.md 重新出图 (plot_gallery EXPERIMENT_ID → v5) + 走 docs-conventions。