跳到主要内容

ISSUE-001: CBFC Credit Return 建模错误导致大消息带宽崩塌

发现日期: 2026-04-15
状态: 已修复,已验证
影响: G5 仿真大消息场景(>64MB)RMSPE 劣化至 132%~659%,小消息不受影响


问题现象

G5 仿真 H200 8-chip Ring AllReduce,对比实测数据(H200 NVLink4):

SizeG5/Meascredit_block 次数slot_exhaust 次数
1 MB0.16x00
4 MB0.32x00
16 MB0.63x00
64 MB0.96x013,042
128 MB1.32x7,81831,028
256 MB6.59x57,56965,024
512 MB4.24x77,354130,560

64MB 精度最佳(0.96x),之后急剧恶化,credit_block 从 0 跳至数万次。

小消息误差来自其他原因(CHS 模式尚未实现),大消息劣化是独立问题。


根因分析

直接原因:CreditReturn 与数据包共享 busy_until_ns

event_handlers.rs 中 CreditReturn 事件通过 c2c_net.transmit() 发送, 与数据包使用同一个 busy_until_ns 串行化队列:

// event_handlers.rs ~line 281
Event::CreditReturn { .. } => {
let arrive = c2c_net.transmit(&rx_name, &next_node, ack_wire_bytes, t)
.map(|r| r.arrive_ns as u64)
.unwrap_or(t as u64);
kernel.schedule_at(arrive, evt);
}

c2c_network.rs 中链路模型:

fn transmit(&mut self, wire_bytes: u64, now_ns: f64) -> f64 {
let contention_wait = (self.busy_until_ns - now_ns).max(0.0);
let start_ns = now_ns + contention_wait;
self.busy_until_ns = start_ns + serialization_ns; // 数据包和 credit 共享
return contention_wait + serialization_ns + self.base_latency_ns;
}

级联效应

双向 Ring AllReduce 中,chip0 → chip1 发数据,同时 chip1 → chip0 也发数据。 chip0 收到数据后需要向 chip1 返还 credit,但 chip0 → chip1 链路被正向数据包 饱和,CreditReturn 必须排在所有数据包后面等待:

450 GB/s 链路,一个 8192-byte 数据包串行时间 ≈ 18 ns
如果队列里有 N 个数据包,CreditReturn 等待 ≈ N × 18 ns

大消息时 N 可达数百,credit return 延迟数 us
-> TX 等不到 credit -> credit_block -> slot_exhaust -> 性能崩塌

为什么小消息不受影响

小消息数据量少,链路未饱和,credit return 几乎零排队,及时返还。


Spec 依据

RC Link spec (RCLINK_AFH_SPEC_v2.4) §5.5 CBFC 流量控制

  • "CREDIT 的返还由 MAC 完成"
  • CBFC_CTRL 的 FREE_CRD 输入来自 MAC 层(硬件信号,非数据包)
  • "CBFC 的反压与 PFC 共用接口" — 通过 TX_PFC_REQ_O[7:0] 端口

PAXI UserGuide (V2R0P5) §2.2

  • "MAC's CBFC/PFC supports 8 Virtual Channels"
  • Credit 信息走 MAC 层 PFC 接口,不是 RC Link 数据通道上的包

结论:Credit return 不走任何 VC,是 MAC 层控制信号。


业界对比

主流 C2C/互联协议均不让 credit return 排在数据队列后面:

协议Credit Return 机制
PCIeUpdateFC DLLP(8 bytes),独立高优先队列,可在任意帧边界插入
CXL嵌入数据 FLIT 头部 2-byte 字段,随数据帧发出
UCIe嵌入 FLIT 帧头 1-bit 信号,每帧边界携带
InfiniBandper-VL 独立管理,不同 VL 互不阻塞

所有协议共同点:credit return 不等数据包队列排空,最多等当前帧结束后插入。


解决方案

方案选择

方案 A(采用):CreditReturn 只经历链路传播延迟(base_latency_ns),跳过 busy_until_ns 串行排队。

理由:

  • 对应 PCIe/PFC 的帧间插入模型
  • Credit 帧极小(64 bytes),在 450 GB/s 下串行时间 0.14 ns,可忽略
  • MAC 层处理 credit,不受数据通道排队影响

方案 B(未采用):给 credit return 独立的 busy_until_ns,不与数据竞争。
更精确但实现复杂,在当前精度目标下不必要。

方案 C(未采用):credit return 完全无延迟。
过于简化,忽略了链路传播延迟。

代码修改

文件: perfmodel/evaluation/g5/src/top/event_handlers.rs

修改 CreditReturn 事件处理,绕过 c2c_net.transmit(),直接加传播延迟:

Event::CreditReturn { chip_id: tx_chip, from_chip: rx_chip, count, vc_id } => {
// Credit return 走 MAC 层 PFC 接口,不走数据包通道
// 只需链路传播延迟,跳过 busy_until_ns 串行排队
let prop_delay_ns = c2c_net.propagation_delay(*rx_chip, *tx_chip)
.unwrap_or(0.0);
let arrive = (t + prop_delay_ns).ceil() as u64;
kernel.schedule_at(arrive, evt);
}

需要在 C2CNetwork 上新增 propagation_delay(from, to) 方法,返回链路的 base_latency_ns


验证方法

  1. 修复后运行 python docs/validation/validate_g5_allreduce.py
  2. 预期:256MB、512MB 场景 credit_block 次数降至接近 0
  3. 预期:大消息 RMSPE 从当前 >100% 降至 <30%
  4. 对比 CHS 模式修复后的整体 RMSPE 目标 <20%

遗留问题

  • 小消息(1-16MB)仍有 0.16x~0.63x 误差,根因是 CHS 内存一致性模式未实现(见 plan floating-gliding-island.md
  • CHS + credit return fix 合并后的整体 RMSPE 待验证