跳到主要内容

ISSUE-035: event_balance 守恒报红 (实际根因是 ISSUE-036 NAK 路径事件丢失,非 cancel_timer 设计)

发现日期:2026-06-05 状态已修复 (实际根因不是 cancel_timer 设计缺陷;修复 ISSUE-036 NAK 路径 let _ bug 后 16/17 测试自动恢复) 类型:误诊 — 原以为 Task 5 守恒模型定义不符 G5 kernel 实际语义,实际是 ISSUE-036 的 NAK 路径 on_ack 返回值丢弃在所有 DCQCN 拥塞场景的副作用 影响范围:G5 multi_chip 集成测试套 16/17 测试报 event_balance != 0 已全部消除。


实际根因澄清 (2026-06-05 ISSUE-036 调查后)

ISSUE-035 的"cancel_timer 设计缺陷"诊断是错的。 实际根因是 ISSUE-036handle_ack_arrived NAK 分支 let (completions, _) = paxi.on_ack(...) 丢弃 RcFrameDone 事件,导致:

  • RcFrameDone 永不调度 → on_tx_done 永不触发 → tx_busy=true 永久 → LG 死锁
  • kernel 事件队列里少了一批应有的 dequeued,events_enqueued > events_dequeued → event_balance 偏差

为什么 16/17 都报 event_balance:这些测试都是 allreduce / alltoall / clos 高拥塞场景,都会触发 DCQCN/NAK 路径,都让一批 RcFrameDone 丢失,event_balance 必然偏移。数值线性放大与 workload 规模相关也由此解释 (NAK 频度 ∝ 拥塞强度 ∝ workload)。

修复后实测 (ISSUE-036 修完):cargo test --release 从 360 passed / 17 failed 升到 377 passed / 0 failed / 3 ignored,所有 16 个 event_balance 报红测试自动恢复。

Lesson Learned:严格无容差守恒断言哲学的胜利 — 当时若按 Plan 选项 B 临时移除 event_balance from CONSERVATION_KEYS 绕过,ISSUE-036 这个真 bug 会继续静默存在。"伪红进去查不加容差" 真把根因逼了出来。

cancel_timer 机制本身不影响守恒 — Task 5 subagent 当时怀疑的 schedule_timer+cancel_timer 不平衡其实在正常路径上是平衡的 (timer 被 cancel 时仍走 pop 路径 +1 dequeued),只是被 ISSUE-036 NAK 路径丢的事件掩盖了。


历史诊断记录 (保留为 lesson 用)

以下是 2026-06-05 调查 ISSUE-036 之前的初步分析,已被推翻。保留供后续 review 学习"症状归因偏差"的典型案例。


问题现象

Phase 1 Task 6 把守恒 helper 套到 17 个集成测试结尾后,16/17 测试 panic,全部报 event_balance != 0,数值随 workload 规模线性放大:

测试event_balance 数值
test_relay_chip_2hop_p2p_completes2
test_switch_port_mapping_from_neighbors18
test_switch_incast_vs_no_contention23
test_switch_ecn_bidirectional_traffic110
test_switch_ecn_dcqcn_feedback119
test_switch_incast_3_to_1133
test_clos_vs_direct_allreduce192
test_2port_allreduce_faster_than_1port552
test_cfs_ring_ar_completes_no_deadlock552
test_cfs_2port_faster_than_1port552
test_cfs_ring_ar_latency_not_less_than_chs552
test_2port_latency_varies_with_n764
test_clos_allreduce_8_chips920
test_clos_allreduce_32_chips15880
test_alltoall_data_conservation_no_frame_drop132026

数值范围 2~132026 与 workload 规模(chip 数 × message 数 × 时长)强相关,提示是正常事件流里的某一类事件没纳入 dequeued 计数


调查过程

  • [查代码] perfmodel/evaluation/g5/src/kernel/sim_kernel.rs Task 5 插桩 5 个点:
    • schedule() / schedule_at() / schedule_timer()events_enqueued += 1
    • run()queue.pop() / pop_next() 成功出队 → events_dequeued += 1
  • [查代码] schedule_timer() 返回可 cancel 的 handle,可通过 cancel_timer() 将事件标为 cancelled。run() / pop_next() 中 cancelled 事件被 pop 后 continue,不计 events_dequeued
  • [假设] Task 5 subagent 当时决策:cancel 路径不豁免,触发即"非自然终止进去查"。但实际通信场景中 schedule_timer + cancel_timer 是合法常规事件流(如 DCQCN rate-block 超时取消、ACK timer 提前到达取消、retry timer 在 ACK 后取消等)——这些是设计预期,不是泄漏。
  • [实验] 数值线性放大与"每个 frame 一个 timer + cancel"的预测吻合(132026 ≈ alltoall 16 chip × 3MB/pair 的 timer 数量级)。

根因分析

sim_kernel.rs 中 cancelled timer 弹出时被跳过,导致 events_enqueued > events_dequeued——但 cancel 本身是设计预期的合法事件流终止方式,不是泄漏。当前 event_balance = enqueued - dequeued 的定义把"cancelled timer 数量"算成"未处理事件",语义错误。

Plan v2 阶段曾在 review NEW-1 (MEDIUM) 标记 events_pending 定义模糊,Plan 写"G5 不支持事件 cancel,不需要例外口子",但该判断错误——G5 确实有 cancel_timer 机制。


Spec / 文档依据

无 G5 spec 锚定事件守恒模型(本 Phase 1 是首次引入)。

设计依据来自 docs/knowledge/04-软件工程实践/02-测试与验证方法论.md 守恒不变式章节,但守恒等式的具体边界(cancel 算不算合法 dequeue)需结合 G5 kernel 实际语义定义。


解决方案

备选方案

方案描述优点缺点
Acancel_timer 时 events_dequeued += 1(把 cancel 当作合法 dequeue)守恒等式回正,无场景豁免失去了"cancel 是否被滥用"的探测能力
Bevents_cancelled 第三个计数器,守恒等式改为 enqueued = dequeued + cancelled完整描述 kernel 状态,可单独追 cancel 量helper 需更新,3 类 stat 而非 1 类
Cevent_balance 移出 CONSERVATION_KEYS,kernel 守恒作为可选指标不强制不引入新代码失去事件守恒兜底层探测,plan 设计意图丢失

采用方案

待 Phase 1.5 决策。倾向 B(完整描述 + 可单独追 cancel),但需先确认 cancel 是否真的全部"合法"。

涉及文件

文件改动说明
perfmodel/evaluation/g5/src/kernel/sim_kernel.rs按选定方案修计数逻辑
perfmodel/evaluation/g5/src/top/multi_chip.rscollect_results 输出新 stat key
perfmodel/evaluation/g5/src/top/multi_chip/test_conservation.rsCONSERVATION_KEYS 列表更新

验证

Phase 1.5 修复后:

  • 16 个原本报 event_balance != 0 的测试应全部恢复绿(假设它们都是合法 cancel 导致)
  • 如果剩 N 个仍红,N 即真 bug 数量,逐个调查

遗留问题

  • 修复时需对账:cancel_timer 是否真的全部"合法",有没有滥用路径(如忘了 cancel 导致超时反复触发)。如果有滥用,方案 A 会掩盖。
  • Phase 2 蜕变测试(MR)上线后,可加一条"event_balance 数量 ∝ workload 规模"的标度性 MR 辅助验证守恒模型正确性。
  • 同时调查 PSN gap 计数语义 (Phase 1 code-review F003 发现):rc_link_rx.rs:186-191 在 NAK 路径每次累加 gap,即同一 lost frame 触发 N 次 NAK 重发会被计 N 次。守恒断言 psn_gaps == 0 在含合法 GBN 重传场景下会 false-positive。17 个 failed 测试中是否有 PSN gap 路径污染需要确认。建议拆 psn_gap_observed(信息性)vs psn_unrecovered_gaps(守恒断言用)。