G5 RC Link 传输层设计规格
版本:1.6.1 状态:Accepted 创建日期:2026-04-21 最后更新:2026-06-04 作者:xiang.li 前置:互联通信G5仿真建模设计规格
变更历史
| 版本 | 日期 | 变更说明 |
|---|---|---|
| 1.5.1 | 2026-06-02 | 修正 §VC 仲裁 RR 推进规则:vc_rr_ptr 只在实际发帧后推进,空 VC / 阻塞不推进 |
| 1.5.0 | 2026-06-01 | 按新模板规范重构:9 节中文 H2 重排,新增 §名词定义 §非功能性需求,完整接口签名/参数表下沉附录 C |
| 1.6.1 | 2026-06-04 | ISSUE-033 实施修正:TX cap 落地为 RcLinkTx frame_send_delay=max(datapath,serdes)(tx_busy 串行使单 LG=line_rate_per_lg);PhyLink per-edge 序列化保留与 per-LG cap 共存(撤 PhyLink chip 出口会 crash single-switch 425→21),撤回 1.6.0 的"撤 chip 出口序列化"+ 判别准则。§打包延迟 stage3/eq:rc-frame-done 已精修对齐 max 语义(datapath/SerDes pipeline 重叠取慢者,PhyLink per-edge 序列化保留共存) |
| 1.6.0 | 2026-06-04 | ISSUE-033:TX SerDes 限速归属由 per-edge PhyLink 修正回 per-LG MAC credit(新增对称 RX 的 §芯片级聚合发送 cap + Goal G8) |
| 1.4.2 | 2026-05-29 | 新增 §芯片级聚合接收 cap,新增 Goal G7 |
| 1.4.0 | 2026-05-13 | ITLV 默认策略改为 hash-based,round_robin 降级为调试 baseline |
| 1.3.0 | 2026-05-12 | 新增 §事件粒度,重写 §打包延迟为 frame-level 序列化 |
| 1.2.0 | 2026-04-28 | 新增 §多 Link Group 并行模型,接口加 lg_id 维度,diag 按 LG 分行 |
| 1.1.0 | 2026-04-21 | 补全流程图与 ECN RED 公式,扩展 Non-Goals 与单元测试场景 |
| 1.0.0 | 2026-04-21 | 初版:RC Link TX/RX 完整设计 + DCQCN 拥塞控制 + 物理链路双队列模型 |
@tbl-spec-rclink-01 文档变更历史
概述
RC Link 是 PAXI 协议栈的传输层,负责芯片间数据的可靠传输、流量控制和拥塞管理。本 spec 定义 G5 仿真中 RC Link 的完整设计:TX 侧的 Slot 管理、PSN 序列号、VC 仲裁、CBFC credit 流控;RX 侧的 PSN 校验、ACK MERGE 汇聚、credit 返还、芯片级聚合接收 cap;物理链路的 REQ/RSP 双队列模型;以及 DCQCN 动态拥塞控制回路。
背景
总 spec 对 RC Link 的描述停留在模块职责和参数表层面,缺少以下关键设计决策:
- DCQCN 标注为"预留"但已完整实现:固定速率窗口 (RateCtrl) 已被动态速率状态机替换,spec 仍描述旧机制
- 物理链路双队列未描述:REQ 和 RSP VC 使用独立序列化队列,ACK 不等待数据包,这是带宽建模的关键假设
- RX 侧 credit 返还策略未明确:NAK 和重复包是否返还 credit 直接影响流控正确性
- 流内 PSN 顺序保证未描述:防止乱序 NAK 风暴的设计决策未记录
- ACK MERGE 需求驱动机制未描述:轮询调度策略影响 ACK 延迟建模
RC Link 是通信仿真精度的核心模块。DCQCN 是拥塞场景下带宽收敛行为的唯一建模手段。这些设计细节必须从设计文档和代码提取到 spec,作为验证基准。
名词定义
| 名词 | 定义 | 与易混淆概念的区分 |
|---|---|---|
| RC Link | Reliable Connection Link (RC Link),PAXI 协议栈传输层,提供可靠传输 / 流控 / 拥塞控制 | 不是物理链路本身(物理串行化由下游 c2c_network PhyLink 承担) |
| Slot | TX 侧追踪一个在途包的资源单元,状态机 Empty/WaitGrant/WaitAck | per-LG 独立,不是 CBFC credit |
| PSN (Packet Sequence Number) | 12-bit 环形序列号,per-(lg_id, dst, qp_id) 独立递增 | EPSN 是 RX 侧期望值;PSN 是 TX 侧分配值 |
| EPSN (expected_psn) | RX 侧为每个 (src_chip, lg_id, qp_id) 维护的下一个期望 PSN | 是 RX 校验基准,不是 TX 的 next_psn |
| QP ID | PAXI RCLINK 硬件可见字段 {XPU_ID, BANK},由 cdma_id 合成 | 不是软件层 thread_id |
| vc_bank | qp_id 低 BANK_W=2 位,决定包落入哪个 VC bank | 是 qp_id 的子字段,不是独立 ID |
| VC (Virtual Channel) | 虚拟通道,TX 按 vc_bank 分类,加权 RR 仲裁 | REQ/RSP 是物理链路 VC;此处指 TX 仲裁 bank |
| LG (Link Group) | 一组 x4 SerDes 构成的独立 C2C 通道,SG2262 每芯片 8 个 | 每 LG 一份 RC Link 实例;不是 VC |
| ITLV | segment 级 LG 选择机制,默认 hash-based | 不是 packet 级散布 |
| frame | PAXI/RCLink 接口最小粒度,= 一个 AXI burst,≤ MPS (4096B) | 是上层事件粒度;packet 是 frame 内重传单元 |
| packet | frame 内 Go-Back-N 重传单元,≤ max_payload (1344B) | 正常路径上不暴露为独立事件 |
| MPS (Maximum Payload Size) | frame 字节数上限,默认 4096B(硬件出处 TXBUFFERSIZE) | 是 frame 上限;max_payload 是 packet 上限 |
| CBFC credit | TX 在途 buffer 占用流控单位,per-(lg_id, dst, vc_id),粒度 256B | 是 in-flight 流控;与 MAC credit(发包节奏)不同 |
| MAC credit | MAC2TX_CREDIT,按 SerDes 线速控制发包节奏 | 不是 CBFC credit(buffer 占用) |
| DCQCN | 基于 ECN/CNP 的动态速率拥塞控制,per-(dst, qp_id) | 替换了固定速率窗口 RateCtrl |
| ECN | Switch 对数据包的概率拥塞标记(RED 函数) | Forward path 信号;CNP 是反馈信号 |
| CNP (Congestion Notification Packet) | RX 检测 ECN 后聚合生成的 64B 反馈包 | 经 RSP VC,触发 TX 乘性减 |
| ACK MERGE | RX 需求驱动的累积 ACK 汇聚机制 | FACK 绕过此机制 |
| FACK (Fast ACK) | 零字节控制包绕过 ACK MERGE 的立即确认 | 零字节,不占 CBFC credit(既不消耗也无返还) |
| Go-Back-N | TX 收 NAK 后从间隙点回退重传的协议 | packet 粒度回滚 |
目标与非目标
目标:
- G1:完整定义 TX 侧 Slot 管理、PSN 分配、VC 仲裁、CBFC 流控的设计细节
- G2:完整定义 RX 侧 PSN 校验、ACK MERGE、credit 返还、CNP 生成的设计细节
- G3:定义物理链路 REQ/RSP 双队列模型和 CreditReturn 免序列化设计
- G4:定义 DCQCN 完整拥塞控制回路(ECN 标记 → CNP 反馈 → 速率调整 → 速率恢复)
- G5:明确 QP ID 编码契约 — qp_id 为 PAXI 硬件可见字段
{XPU_ID, BANK},由 cdma_id 和 vc_bank 合成,不依赖软件层 thread_id - G6:定义多 Link Group 并行模型 — 单流可通过 N 个独立 RC Link 实例 (per-LG) 散布到多 LG,每实例维护独立的 PSN/CBFC credit/Slot 池/Retry counter;保证单 LG 内严格保序,跨 LG 独立无干扰
- G7:定义 RX 端芯片级聚合接收 cap — 镜像 TX 芯片级聚合发送 cap,约束单芯片数据接收聚合带宽 ≤ num_link_groups × line_rate_per_lg,按 per-LG 并行接收串行化,控制包(payload=0)绕过
- G8:定义 TX 端芯片级聚合发送 cap — per-LG MAC credit 按 SerDes 线速
line_rate_per_lg串行化(RcLinkTxframe_send_delay = max(datapath, wire/line_rate_per_lg),tx_busy 串行使单 LG = line_rate_per_lg),chip 8 LG 并行 -> 聚合 ≤ num_link_groups × line_rate_per_lg = 400。SerDes 限速绑定 LG(数量 = num_link_groups,SG2262 为 8,不随拓扑 edge 数变化)。与 PhyLink per-edge 序列化共存:chip 出口吞吐 binding = per-LG cap(50/LG),PhyLink edge(400)在多 edge 下不 binding、single edge 下与 per-LG 共同 400,无 double-throughput(busbw ≤ 400)。与 G7 RX cap 对称。(实施修正:初版拟撤 PhyLink chip 出口序列化,验证证明会 crash single-switch,改为保留共存,见 ISSUE-033)
非目标:
- PFC 链路级流控(需要 switch → chip 的 PAUSE 帧反向信令,复杂度高,已明确延后)
- 多播 (TYPE2) 流控(双重约束模型,当前仿真不涉及多播)
- 报文格式选择(AFH_Lite / Standard / AFH_GEN1 / AFH_GEN2_16b 的开销差异,当前使用固定 header_overhead)
- RNR (Receiver Not Ready) 重传机制(硬件有 rnr_retry_counter,仿真中接收端始终 Ready,无 RNR 场景)
- P_key 分区隔离(安全/多租户机制,性能仿真不涉及)
- TYPE3 原始以太网报文(软件管理的 MD 机制,不在通信仿真范围内)
- LITE 模式组网(不做端到端重传保护,QPID 编码不同,当前仿真仅支持标准模式)
- 中断系统(MSI/电平中断定义属于硬件寄存器规格,仿真不建模中断)
用例说明
一个包从 TX 发出到 RX 确认的完整旅程
假设 Chip 0 的 PAXICore 已完成 MPS 分段,生成了一个 1344B payload 的 SegmentInfo,提交给 RC Link TX:
-
TX 分配 Slot:从 512 个 Slot 池中找到一个 Empty Slot,分配 PSN(per-(dst=1, qp_id=3) 递增),Slot 状态变为 WaitGrant,包入 VC Bank3(因为 qp_id & 3 == 3)的待发队列
-
TX VC 仲裁:加权 RR 轮到 Bank3,检查 CBFC credit 充足(消耗 6 个 credit,因为 ceil((1344+50)/256) = 6),检查 DCQCN 速率允许(now >= last_send + min_interval),三项都通过
-
TX 打包发送:Slot 状态变为 WaitAck,打包延迟 = ceil(1394/64) = 22 ns,生成 RcPackDone 事件
-
物理链路传输:包进入 REQ VC 队列,经历排队等待 + 序列化 + 传播延迟,到达对端(或 Switch)
-
RX 收包校验:PSN == expected_psn,校验通过。返还 6 个 credit(延迟 1ns)。包入 ACK MERGE 队列,调度 AckMergePoll
-
RX ECN 检查:如果包的 ecn_marked == true,检查 CNP 聚合窗口(距上次 CNP >= 2500ns),满足则生成 CnpReceived 事件
-
ACK 反向传输:AckMergePoll 触发,生成累积 ACK(覆盖所有已收包)。ACK 进入 RSP VC 队列(独立于 REQ,不等数据包),沿反向路由传回 TX
-
TX 处理 ACK:释放 Slot(WaitAck → Empty),通知 PAXICore on_packet_acked
端到端时序图
下图展示一个包从 PAXICore 提交到 RC Link TX、经物理链路传输、由 RX 确认的完整时序:
详细设计
作用域说明:§Slot 管理 / §PSN 管理 / §VC 仲裁 / §CBFC 流控 / §打包延迟 描述的规则作用于单个 LG 实例内部——多 LG 配置下每个 LG 独立持有自己的 Slot 池、PSN 计数、credit 账本、retry counter、VC 仲裁状态。LG 之间状态完全独立。多 LG 整体设计见 §多 Link Group 并行模型。完整接口签名、调用关系、参数默认值见附录 C。
Segment Dispatch 机制
Segment 从 PAXI Core 的 segment_queue 喂入 RC Link TX 的 vc_pending 是 event-driven push,不是 polling。这是硬件 spec 的 push 语义要求,也是 event-driven 仿真器的业界共识。
硬件 spec 依据
RCLINK_AFH_SPEC v2.4 §5.10 (P36L11 / P37L5):
上游下发的 TYPE1 数据报文会顺序进入一个队列中... 有上游下发新的数据报文写入队列时,该 slot 由 EMPTY 变为 WAIT_GRANT。
硬件 layer 2(队列接口)上,slot 状态由 "上游下发"事件 直接驱动,没有"polling 检查上游是否就绪"这一步。反压通过物理信号(FLOW_STOP / CBFC credit)实现,见 §CBFC 流控。
CDMA 端的 SerDes 物理串行化在仿真器层离散化为 segment + earliest_ready_ns,但 segment 的"物理就绪 → 喂入 slot"仍应按 push 语义触发,不应反复 polling 探测。
触发事件清单
| 物理事件 | 仿真事件 | 作用 |
|---|---|---|
| CDMA 提交新 transfer(分段产生 segment) | submit handler 内部计算 next_dispatch_at | 提交时刻 push 喂入 + schedule 下一次 dispatch |
| 对端 ACK 到达释放 slot | on_ack handler 内部计算 next_dispatch_at | slot 释放 → capacity 增 → 可能可喂入更多 |
Segment 在 earliest_ready 时刻物理就绪 | SegmentDispatch event 触发 | 之前 feed_rc_link 计算的 next_t 时刻 |
| Datapath busy 释放(handle_rc_frame_done → on_tx_done) | 内部 try_arbitrate 接续发下一帧 | 不需要单独 dispatch event |
@tbl-segdispatch-triggers SegmentDispatch 触发事件清单
单一未决事件 + 防重 schedule
每个 chip 维护单一未决 SegmentDispatch timer:
feed_rc_link(now)末尾返回next_dispatch_at = min(segment_queue.front().earliest_ready_ns, ...)- 调用方(caller)拿到
next_dispatch_at后,通过reschedule_segment_dispatchhelper:- 若 chip 有已 schedule 的 timer →
kernel.cancel_timer(old_id) - 若
next_dispatch_at在未来 →kernel.schedule_timer(target, SegmentDispatch)存新 id
- 若 chip 有已 schedule 的 timer →
SegmentDispatchhandler 触发时:清掉 timer_id →feed_rc_link→ 仲裁所有 LG → 重 schedule
此模式借鉴 ns-3 QbbNetDevice m_nextSend.IsExpired(),保证:
- wake 数 = 物理事件数:不再有 polling self-reschedule 膨胀
- latency 与仿真步长无关:每次 dispatch 时刻由物理参数(
earliest_ready_ns)决定,与"任何噪音事件"是否插入无关 - 符合硬件 layer 2 push 语义:slot WAIT_GRANT 状态变化绑定真实 dispatch 时机
反例(已废弃)
旧实现使用 polling-driven RcLinkWake self-reschedule:
on_event(RcLinkWake) → feed_rc_link → schedule(RcLinkWake, next_wake) // self-loop
此模式让 wake 数膨胀(tok=1024 N=64 达数千万次),且 segment 喂入时刻耦合 wake 频率,造成 latency 数值漂移。SegmentDispatch 替代后,wake 数严格 = 物理就绪事件数,符合 spec 与业界(ns-3 / htsim / OMNeT++ INET)实践。
详见 ISSUE-031 调研:docs/issues/ISSUE-031/{spec-true-semantics,des-dispatch-mechanisms,refactor-proposal}.md。
TX 侧设计
Slot 管理
TX 维护一个大小为 TYPE1_OST(默认 512)的 Slot 池(per-LG 独立)。每个 Slot 有三个状态:
Empty → WaitGrant → WaitAck → Empty
↗ (NAK: Go-Back-N 回退)
- Empty → WaitGrant:分配 Slot 时记录 (dst, qp_id, psn, payload, txn_id, vc_id),分配 PSN(per-(dst, qp_id) 递增),包入对应 VC 的待发队列
- WaitGrant → WaitAck:VC 仲裁胜出后,消耗 CBFC credit,计算打包延迟,生成 RcPackDone 事件
- WaitAck → Empty:收到覆盖该 PSN 的累积 ACK 后释放
- WaitAck → WaitGrant:收到 NAK 时 Go-Back-N 回退
Slot 耗尽时,新包入 PAXICore 的 segment_queue 排队(见 PAXICore spec),ACK 释放 Slot 后由 PAXIBridge.feed_rc_link() 自动 drain。
PSN 管理
12-bit 环形序列号 (0-4095),per-(lg_id, dst, qp_id) 独立计数——每个 Link Group 实例维护自己的 PSN 序列空间,跨 LG 互不干扰。半区判定用于比较:
$$\begin{equation} \text{before}(a, b) = 0 < (b - a) \bmod 4096 < 2048 \label{eq:rc-psn-before} \end{equation}$$ACK 为累积确认:ack_psn 表示该值之前的所有 PSN 已确认。
QP ID 编码:qp_id 是 PAXI RCLINK 层硬件可见字段 {XPU_ID, BANK}(PAXI RCLINK spec P37 L30 — LITE mode Source_qpid 字段定义同此格式,标准模式遵循同一布局)。仿真中按下式从 cdma_id 合成:
其中:
- $\text{cdma\_id}$:当前 CDMA 实例的 chip 内 XPU 编号
- $\text{BANK\_W} = 2$:bank 索引位宽(4 个 VC bank)
- $\text{NUM\_BANK} = 2^{\text{BANK\_W}} = 4$:bank 数量
- $\text{vc\_bank} = \text{cdma\_id} \bmod \text{NUM\_BANK}$:本 CDMA 落入的 VC bank
为什么 qp_id 必须基于硬件可见字段:软件层 thread_id 是 CDMA 内部命令调度概念,不出现在 PAXI/RCLINK 报文头。RX 侧通过报文头中的 qp_id 字段路由到对应 EPSN 上下文,必须与硬件一致。若 qp_id 用 thread_id:(a) 不同 CDMA 的 thread_id 可能撞号,导致 RX 端 EPSN 串扰;(b) 软件改变线程划分会破坏 PSN 空间分配,违反"软件改动不应影响硬件协议"。基于 {XPU_ID, BANK} 编码与 hash ITLV 输入对齐(见 §ITLV 分发机制),是硬件契约。
PSN 空间和 DCQCN 状态因此是 per-(lg_id, dst, qp_id)——粒度为 (target chip, link group, source XPU × bank),与硬件 RC Link 上下文一一对应。
为什么 PSN 必须 per-LG:N 个 LG 并行打包同一流的不同 segment 时,各 LG 的包几乎同时进入 c2c 物理链路并被序列化,到达 RX 顺序与全局 PSN 顺序不一致。若所有 LG 共享一个 PSN 序列,会触发 PSN gap → NAK 风暴。per-LG 独立 PSN 保证 RX 端按 (src_chip, lg_id, qp_id) 分别校验,单 LG 内顺序天然成立,跨 LG 无保序约束。这也是 IB dual-port HCA / NVLink multi-sub-link 的实际硬件做法。
VC 仲裁
5 个虚拟通道,按 qp_id 低位 vc_bank 字段分类(vc_bank = qp_id & (NUM_BANK-1),即 qp_id 的低 BANK_W=2 位,对齐 §PSN 管理 中的 qp_id 编码):
| VC | 权重 | 分类规则 |
|---|---|---|
| Bank0 | 1 | vc_bank == 0 |
| Bank1 | 1 | vc_bank == 1 |
| Bank2 | 1 | vc_bank == 2 |
| Bank3 | 1 | vc_bank == 3 |
| MUL | 256 | 多播(当前未使用) |
@tbl-spec-rclink-02 TX 侧 VC bank 分类与仲裁权重(区别于 RCLINK 物理 8 VC)
加权 RR 机制:vc_rr_ptr 指向当前轮到的 VC,vc_rr_counter 记录已发配额。指针只在实际发出报文后推进 —— 发一帧 counter++,达 weight 则指针前进到下一个 VC 并重置 counter;跨空 VC 切到新 VC 发帧时重置 counter。空 VC、credit 阻塞、rate 阻塞均跳过找下个 VC,但不推进指针、不动 counter。RR 状态绑定实际发送而非仲裁尝试次数,对齐硬件 RCLINK_AFH_SPEC §5.10「每次发出一个报文后」更新 bank mask 的语义;event-driven 仿真中若空扫也推进指针,RR 会耦合唤醒密度,使 latency 出现伪差。
仲裁决策流程(每个 VC 内):
- 取 VC 队列中的第一个 WaitGrant 包
- 检查 CBFC credit 是否充足
- 检查 DCQCN 速率是否允许
- 任一检查不通过 → 该包阻塞
流内 PSN 顺序保证:若某个 (dst, qp_id) 的 head-of-flow(队列中第一个 WaitGrant 包)被 credit 或 rate 阻塞,则同一 (dst, qp_id) 的所有后续包在本轮仲裁中全部跳过。这防止同一流内的乱序发送——乱序到达 RX 端会触发 PSN 间隙检测,产生不必要的 NAK 风暴。不同 (dst, qp_id) 的包仍可在同一 VC 内交错发送。
下图展示 TX 仲裁的完整决策流程,包括 LG 选择、credit 检查和 PSN 顺序保证:
与硬件仲裁的建模差异:硬件使用 bank mask 轮转机制(发包后按 qpid_msb 排除同 bank 的其他 Slot),G5 仿真简化为加权 RR。两者在公平性语义上等价——都确保各 bank 获得均等的发送机会——且都在「实际发出报文后」推进 RR 状态(硬件更新 bank mask / 仿真前进 vc_rr_ptr),不绑定仲裁尝试次数。微观单包调度顺序因 RR 实现不同而有差异;仿真关注宏观带宽分配和拥塞行为,单包顺序差异对 latency 的影响在 0.1-2% 量级。
CBFC 流控
Per-(lg_id, dst, vc_id) 粒度(每个 LG 实例独立维护与对端 RX 的 credit 账本),单位 credit_size(默认 256B)。
发送一个 packet 所需的 credit 数量由 payload 大小和包头开销决定:
$$\begin{equation} C = \lceil (\text{payload\_bytes} + \text{pkt\_ovhd}) / \text{credit\_size} \rceil \label{eq:rc-cbfc-credit-consume} \end{equation}$$其中 pkt_ovhd 对应硬件的 PktOvhd 寄存器(有符号 10-bit),仿真中简化为 header_overhead(默认 50B)。
发送检查:剩余 credit >= 消耗量 + CREDIT_UF_LIMIT。CREDIT_UF_LIMIT(默认 1)确保至少保留一个最大包的 credit 余量,防止过度消耗导致反压失效。
初始 credit:仿真组装时统一设置,每个 LG 各 1024 个 credit 单位(默认)。N=8 配置下,每对芯片每 VC 共 8192 credit × 256B = 2 MB 缓冲深度。
事件粒度:frame-level 事件 + packet-level retry
PAXI SUE2.0 UserGuide §2.1.1 Flit Rules 规定 PAXI 把整个 AXI burst 打包成一个 frame("Paxi packages the entire write or read burst into a single frame and transmits it to the rclink"),frame 是 PAXI/RCLink 接口的最小粒度。MPS(Maximum Payload Size,默认 4096B)是 frame 字节数上限。
在 RC Link 内部,frame 进一步切成 packet(≤ max_payload,默认 1344B),但packet 仅是 Go-Back-N 重传粒度(PAXI UserGuide 中 TYPE1_PKT_LEN 的语义),不是 datapath 上的独立事件。MAC datapath 是字节级 pipeline,frame 内相邻 packet 在 datapath 上连续 line-rate 串行触发,无包间 stall。
| 粒度 | 大小 | 角色 | 事件 |
|---|---|---|---|
| Frame | ≤ MPS (4096B) | 上层接口、序列化时间计算单位、CBFC credit 上报、ACK 通知 PAXICore | RcFrameDone(frame 整体进入 wire 完成)/ RcFrameAcked(远端 burst 响应回到) |
| Packet | ≤ max_payload (1344B) | Go-Back-N 重传单位、PSN 单调递增追踪 | 仅在 retry/NAK 路径触发包级事件,正常 path 上不暴露 |
@tbl-spec-rclink-event-granularity 事件粒度分层
契约约束:
- 上层(PAXICore)只感知 frame 级事件;packet 级状态对外不可见
- frame 内多 packet 共享原子 slot 组:frame 整体占用 slot 组,frame 完成(含全部 packet ACK)后整组释放
- frame 内 packets 在 datapath 上连续串行;datapath 占用时间 = frame 整体序列化时间
- 重传时按 packet 粒度回滚(保留 PAXI UserGuide TYPE1 协议语义)
打包延迟与 MAC Credit
frame 发送在发送芯片内经历两段串接:NoC datapath 打包 + SerDes 序列化。RC Link TX 内部 datapath 占用时间按 frame 整体计算,仅覆盖 NoC 端进入 datapath FIFO 的打包时间;SerDes 物理串行化由 per-LG MAC credit 承担(chip 固定 8 个 LG/MAC,各按 line_rate_per_lg 释放 MAC2TX_CREDIT,聚合 chip 级上限,详见 §芯片级聚合发送 cap),不是 per-edge 物理链路(edge 数随拓扑变,LG 固定 8,见 §芯片级聚合发送 cap 的"为什么 per-LG 而非 per-edge"):
其中 frame_wire_bytes = frame_payload + frame_header_overhead(包括 packet 切分产生的逐包 header 累加,但 frame 整体作为一个事件触发完成时刻)。
两级延迟——芯片内 MAC(阶段 1 datapath 与阶段 2 SerDes 取慢者,per-LG)+ 物理链路(阶段 3 PhyLink per-edge 序列化 + 传播):
| 阶段 | 模块 | 公式 | 物理含义 | 粒度 |
|---|---|---|---|---|
| 1. NoC datapath | RC Link TX | $T_{\text{frame\_send}} = \lceil \text{wire}/\text{datapath} \rceil$ | MAC 从 NoC 拉数据进 datapath FIFO 的占用时间 | per-LG |
| 2. SerDes 序列化 | per-LG MAC credit | $T_{\text{tx\_serialize}}$(见 eq:rc-tx-serialize) | SerDes 字节级 line-rate 串行化,受 MAC2TX_CREDIT 节奏控制;与阶段 1 pipeline 重叠取慢者(见 eq:rc-frame-done);chip 8 LG 并行 → 聚合 cap = num_link_groups × line_rate_per_lg | per-LG(chip 8 个) |
| 3. 物理链路 | c2c_network PhyLink | $T_{\text{phy}} = \text{wire}/\text{bandwidth} + \text{base\_latency}$ | per-edge 序列化 + 传播,对所有 edge 生效(保留共存,零改动);chip 出口吞吐 binding = 阶段 2 per-LG cap,PhyLink edge 非 throughput-binding | per-edge |
@tbl-spec-rclink-frame-pipeline frame 端到端三段串接
frame 完成时刻(datapath 与 SerDes 取慢者,tx_busy 串行)——NoC datapath 与 per-LG SerDes 在 MAC 内 pipeline 重叠(非串接累加,避免 double-count),frame_send_delay 取二者慢者;tx_busy(bool) 在 frame_send_delay 期间串行化本 LG(serdes 50 < datapath 64 → serdes binding,单 LG 稳态吞吐 = line_rate_per_lg,chip 8 LG 并行聚合 = 400):
事件时序:RcFrameDone($T_{\text{RcFrameDone}}$,见 eq:rc-frame-done)→ handle_rc_frame_done 触发 PhyLink → C2CLinkDone($+ T_{\text{phy}}$)→ RX 端 per-LG 接收串行化 + frame ACK 聚合。
ISSUE-033 修正:1.3.0(frame-level 重构)曾把 SerDes 序列化交给 per-edge PhyLink(
T_phy = wire/line_rate + base_latency),与 §芯片级聚合发送 cap 的 per-LG MAC credit 表述矛盾。原始 spec RCLINK_AFH_SPEC §7.4.1 证明 SerDes 限速是 per-LG(per-MAC),故本版改回 per-LG(RcLinkTxframe_send_delay = max(datapath, wire/line_rate_per_lg),tx_busy 串行使单 LG = line_rate_per_lg)。PhyLink per-edge 序列化保留并共存:chip 出口吞吐 binding = per-LG cap,PhyLink edge 不 double-限吞吐(多 edge 不 binding / single edge 共同 400)。(1.6.1 实施修正:初版拟撤 PhyLink chip 出口序列化,验证证明 crash single-switch 425→21,改为共存,见 ISSUE-033)
硬件中 MAC 通过 credit 机制(MAC2TX_CREDIT_I,RCLINK_AFH_SPEC SS7.4.1)控制发包节奏:MAC 按 SerDes 线速字节级 pipeline 处理 frame 内容,frame 内相邻 packet 之间不产生额外 stall(MAC2TX_CREDIT 在 frame 序列化过程中按节拍连续释放)。frame 完成时 MAC 释放该 frame 占用的全部 credit。
SG2262 默认配置下,满 frame (4096B payload + 4 packet × 50B header ≈ 4296 wire bytes):
- $T_{\text{frame\_send}}$(RC Link TX)= $\lceil 4296/64 \rceil$ = 68 ns
- $T_{\text{phy}}$(PhyLink)= $4296/50 + 25$ = 110.9 ns
- 端到端 = 68 + 110.9 = 178.9 ns
frame 内最后一个 packet 字节数不影响 $T_{\text{frame\_send}}$ 的连续性——小尾 packet 仅减少该 frame 的 wire_bytes 总量,不在 frame 内部产生额外 stall。frame 序列化期间该 LG 的 TX datapath 标记为忙,不处理新 frame;其它 LG 仍可并发处理新 frame。
多 Link Group 并行模型
硬件背景:SG2262 每芯片有 8 组 x4 SerDes Link,构成 8 个独立的 C2C Link Group (LG)。每 LG 由独立 MAC + PCS + FEC + SerDes 组成,与 PAXI Core 通过 NoC switch 解耦(CDMA → NoC → 任意 MAC,many-to-many)。同一笔通信可以散布到多个 LG。
建模结构
PAXI Core (1 个, 共享)
├─ AXI 事务管理 (W/R OST 总池)
├─ MPS 分段 (transaction → segments)
└─ ITLV LG 选择 (segment 级)
↓
RC Link[0..N-1] ← N 个独立实例 (每 LG 一份)
每实例独立持有:
├─ Slot 池 (TYPE1_OST 个, per-LG 独立)
├─ PSN 序列 (per-(dst, qp_id), 在该 LG 内独立计数)
├─ CBFC credit (per-(dst, vc_id), 该 LG 与对端 RX 的账本)
├─ Retry counter (per-(dst, qp_id), 该 LG 的 Go-Back-N 状态)
├─ VC 仲裁状态 (vc_rr_ptr, vc_rr_counter)
└─ DCQCN per-QP rate state (per-(dst, qp_id))
↓
TX datapath[0..N-1] ← N 个独立物理通道
├─ tx_busy 标志 (per-LG)
├─ 单 LG datapath_bytes 决定 pack_delay
└─ 单 LG line_rate 决定 DCQCN 速率上限
RX 侧对应 (per-(src_chip, lg_id, qp_id)):
├─ expected_psn (EPSN)
├─ ACK MERGE pending 队列
└─ pending CNP 状态
控制层共享 vs 数据层独立:
| 层 | 状态 | 归属 |
|---|---|---|
| 共享 (PAXI Core) | W/R OST 总池,MPS 分段,segment 完成聚合 | 1 个实例 |
| 独立 (RC Link, per-LG) | PSN 序列,Slot 池,CBFC credit, retry counter, VC 仲裁状态,DCQCN per-QP rate, EPSN (RX) | N 个实例 |
@tbl-spec-rclink-03 多 Link Group 并行模型:层,状态
ITLV 分发机制
分发粒度:segment 级(PAXI Core 切出 segment 时即决定走哪个 LG),不是 packet 级。
为什么 segment 级而不是 packet 级:同一 segment 的多个 packet 在同一 LG 内连续打包,PSN 连续递增。若 packet 级散布会破坏单 LG 内的 PSN 单调性(同一 segment 的 PSN 0,1,2 散到不同 LG,每 LG 看到 PSN 不连续)。segment 级分发自然保证单 LG 内 PSN 严格递增。
LG 选择策略(默认 = hash-based ITLV):
PAXI Core 在 submit() 切 segment 时,对每个 segment 计算 lg_id = hash(txn_id, frame_seq, qp_id) % num_link_groups。
| 策略 | 说明 | 适用 |
|---|---|---|
| hash_itlv (默认) | lg_id = mix64(txn_id, frame_seq, qp_id) % num_lg,伪随机均匀分布 | 生产路径,对齐硬件 spec |
| round_robin | 按 chip-level lg_rr_counter 轮转,每 segment 递增 | 仅调试/baseline,存在周期共振问题 |
| least_busy_lg | 选 tx_busy_until_ns 最小的 LG | 历史选项,try_arbitrate 反馈会导致负载不均(已弃用) |
| hash(qp_id) | 同 QP 固定到一个 LG | per-flow affinity 调试 |
@tbl-spec-rclink-04 多 Link Group 并行模型:策略,说明
为什么默认 hash-based:
- 硬件 spec 明确要求 hash:SG2262 C2C 方案规定"多个 c2c Link 之间做 ITLV (Hash)...同 src macid + 同 dst macid + 同 hash value 时路径相同且严格保序"。硬件支持 ITLV 粒度 1, 2, 4, 8, 16, 3, 6, 12 包,均使用 hash 索引,不是 round-robin counter。
- round-robin 存在周期共振:当 chip 内多个 unit 顺序 submit、每 unit segment 数恰好整除
num_link_groups时,所有 unit 的 frame_seq=k 全部被分配到同一 LG。叠加 CDMA 注入门控的阶梯earliest_ready_ns(每 segment 间隔mps/bandwidth_ns),高 frame_seq LG 整体延后,critical path 拉长,导致仿真延迟 vs 消息大小非单调。 - hash 的频谱平坦:伪随机分布让任何 segment 数 mod LG 数都不会锁相,frames 在 LG 上均匀分布,wire 利用率近 100%。
- 业界对齐:ECMP / CMS / RoCE flow steering 全用 hash(CRC32/Toeplitz/FNV/jump hash 等),不用 round-robin counter。
hash 函数实现要求:
- 输入:
(txn_id: u64, frame_seq: u32, qp_id: u16)三元组 qp_id必须使用 §PSN 管理 定义的硬件可见编码({XPU_ID, BANK}),不可使用软件层 thread_id。理由:硬件 RC Link 报文头携带的就是该字段;hash 输入若与硬件不一致,仿真的 LG 分布会与硬件分布偏离,破坏带宽建模的可比性- 输出:
u32或u64,取% num_link_groups作为 lg_id - 性质:雪崩特性(输入 1 bit 改变 → 输出半数 bit 改变),无明显周期共振
- 推荐实现:splitmix64 / FNV-1a 64 / xxhash3,禁止使用
(txn_id + frame_seq) % num_lg这种线性组合(仍有共振)
保序保证:同一 (txn_id, frame_seq) 总是 hash 到同一 LG(hash 确定性),保证单 frame 内 packet 顺序;不同 frame 散到不同 LG 时由 RX 端 per-LG 独立 PSN 校验保证。
为什么 hash 优于 round-robin(设计原理)
核心反直觉:直觉上 round-robin "完美均匀分布",hash 有"碰撞",应该 RR 更优。实际上均匀的输入分配 + 有时间结构的 workload = 结构化负载——RR 把"输入序列的均匀性"传递成"负载时序的相位锁定",hash 反而打破这种锁定。
频谱特性对比:
| 特性 | Round-Robin | Hash |
|---|---|---|
| 总数分布 | 完美均匀 | 近似均匀(有碰撞) |
| 频谱 | 单频强峰(基频 = 1/N_LG) | 平坦(白噪声) |
| 周期性 | 确定周期 N_LG | 无周期 |
| 与周期性 workload 的相互作用 | 共振(aliasing) | 独立 |
@tbl-spec-rclink-itlv-spectrum hash vs round-robin 频谱特性
这是采样定理的另一种表现:周期性采样 + 周期性信号 → aliasing。当上游 workload 具有时间结构(如多源顺序 submit、CDMA 注入门控阶梯 earliest_ready),RR 的固定周期会与 workload 周期共振。
Phase lock 数学模型:
设 N_unit 个上游源顺序 submit,每源切出 K 个 frame;每 frame 的就绪时刻满足
$$\begin{equation} t_i = T_0 + i \cdot \Delta t, \quad i \in \{0, 1, ..., K-1\} \label{eq:itlv-ready-time} \end{equation}$$其中 Δt 是 segment 注入间隔(= MPS / 注入带宽)。
RR 模式(K mod N_LG = 0,发生共振):
每源耗尽 N_LG 的整数倍轮次,每源结束时 counter 回到原点。因此 LG_k 仅接收所有源的 frame_seq=k:
$$\begin{equation} \text{LG}_k \text{ 收到的 frames}: \{(u, k) : u \in \text{所有源}\}, \quad k \text{ 固定} \label{eq:spec-g5-rclink-frame-receive} \end{equation}$$这些 frame 的就绪时刻全部等于 $T_0 + k \cdot \Delta t$(同一时刻),LG_k 的"起跑线"被推后 $k \cdot \Delta t$。
最坏情况 LG(k = N_LG − 1)的 critical path:
$$\begin{equation} T_{\text{crit}}^{\text{RR}} = T_0 + (N_{LG}-1) \cdot \Delta t + N_{\text{unit}} \cdot t_{\text{wire}} \label{eq:itlv-rr-crit} \end{equation}$$Hash 模式:
LG_k 收到的 frames 的 frame_seq 在 {0, ..., K−1} 上近似均匀分布。这些 frames 的就绪时刻分布在 $[T_0, T_0 + (K-1)\Delta t]$,期望 $\frac{K-1}{2}\Delta t$,标准差 $\sigma = \sqrt{\frac{(K-1)^2}{12}}\Delta t$。
critical path:
$$\begin{equation} T_{\text{crit}}^{\text{hash}} \approx T_0 + \frac{K-1}{2} \cdot \Delta t + N_{\text{unit}} \cdot t_{\text{wire}} + O(\sigma) \label{eq:spec-g5-rclink-hash-critical-time} \end{equation}$$差距(K = N_LG 时):
$$\begin{equation} T_{\text{crit}}^{\text{RR}} - T_{\text{crit}}^{\text{hash}} \approx \frac{N_{LG}-1}{2} \cdot \Delta t \label{eq:itlv-rr-hash-gap} \end{equation}$$N_LG = 8、Δt = 64 ns 时约 224 ns 差距——这部分是 RR 引入的人工拖尾,不反映真实硬件行为。
物理类比:3 相电网平衡:
| 场景 | 3 相 RR 模式(电器同步轮转) | 3 相 hash 模式(电器随机开关) |
|---|---|---|
| 各相平均功率 | 完全均衡 | 完全均衡 |
| 各相瞬时尖峰功率 | 集中爆发(同时刻多电器开机) | 打散(随机分布) |
| 系统所需变压器容量 | 必须按尖峰设计(大) | 按平均设计即可(小) |
@tbl-spec-rclink-itlv-power-grid 3 相电网类比 ITLV 策略选择
ITLV 中 LG 就是这 N_LG 相。RR 让所有源的 "第 k 帧" 在同一时刻进入 LG_k,造成 LG_k 内部尖峰累积。hash 把负载在时序上打散到所有相。
碰撞 vs Phase lock:统计性 vs 结构性 hot spot:
担心 hash 碰撞会让某些 LG 过载是合理的,但定量地:
- Hash 碰撞:是统计性的不均匀。LG 负载偏差 ∝ $\sqrt{N}$(大数定律),N 足够大时偏差被平均掉
- RR Phase lock:是结构性的不均匀。LG 负载偏差 ∝ $N$(最坏 LG 负载比平均大 1 个 Δt 阶梯),且不随 N 增大而消失
结构性 hot spot 比统计性 hot spot 严重得多,尤其在 workload 具有规则时间结构时(CDMA 注入门控就是典型的规则时间结构)。
仿真器视角的特殊性:真实硬件靠 PHY clock skew、router queue jitter、SerDes 时钟漂移等"物理噪声"自然打散周期共振。仿真器没有这些物理噪声源,必须在算法层显式引入伪随机性(hash)才能让仿真行为接近真实硬件的稳态分布。
跨 LG 事务完成保证
同一 transaction 的多个 segment 散到不同 LG,每个 segment 有独立 txn_id。PAXI Core 收齐所有 segment 的 ack 后才视为 transaction 完成(生成 DataArrived 事件给上游 CDMA)。跨 LG 的 ack 无序到达不影响 transaction 语义——只是 OSTD 窗口允许的乱序完成。
芯片级聚合发送 cap
每个 LG 的发包速率受 MAC credit 约束(RCLINK_AFH_SPEC §7.4.1 MAC2TX_CREDIT_I):MAC 按 SerDes 线速 line_rate_per_lg 序列化完当前 frame 后才释放 credit,TX 无 credit 不可发下一 frame。每个 LG 维护独立发送串行化时间线(与 RX §芯片级聚合接收 cap 对称)。单 frame 发送串行化延迟:
每个 LG 的发送时间线按 busy 语义推进(镜像 RX eq:rc-rx-serialize):时刻 now 准备发送的 frame,发送完成时刻 = max(now, tx_lg_busy) + T_tx_serialize,并据此更新该 LG 的 tx_lg_busy。芯片级聚合发送带宽因此受限为 N 个 LG 串行化速率之和:
SG2262:8 × 50 = 400 GB/s(与 SG2262 spec intra_bw = 400 GB/s 一致;与 RX 聚合上限相等,因收发共用同一组全双工 SerDes)。
为什么 per-LG 而非 per-edge:chip 物理出口是 8 个固定 SerDes 通道(LG),无论拓扑给它接几条 edge。SerDes 限速绑定 LG(MAC),与拓扑链路(edge)无关。若把发送序列化放在 per-edge 物理链路(如 1.3.0 frame-level 重构曾将 SerDes 交给 PhyLink),高 chip_radix 拓扑(cpb=8 板内 mesh / torus)下 chip 出向聚合 = edge 数 × per-edge 带宽,突破物理 8 × line_rate_per_lg(ISSUE-033 实测 chip0 TX 620-700 GB/s >> 400)。与 RX §芯片级聚合接收 cap 的 per-LG 设计完全对称。
控制包绕过:与 RX 对称,零字节控制包(FACK/ACK/NAK/CNP/CreditReturn)不占发送数据 cap。
关键性质(与 RX 对称):
- N 条独立流:每流分配到一个 LG,N 流并行用满 N × line_rate_per_lg
- 单流:通过 segment 级 ITLV 散布到多 LG,单流也能用满聚合带宽
- N=1 退化为单 LG,所有 PSN/credit/Slot/SerDes busy 在单实例聚合
实现要求:在 RcLinkTx(per-LG 实例)try_arbitrate 中 frame_send_delay = max(datapath_delay, wire/line_rate_per_lg);tx_busy(bool) 已串行化本 LG,故单 LG 吞吐 = line_rate_per_lg(serdes 50 < datapath 64,serdes binding),chip 8 个 RcLinkTx 并行 -> 聚合 400。tx_serdes_line_rate_per_lg 经 PAXIConfig 从芯片 YAML 注入(复用 paxi.tx.line_rate_per_lg,收发共用全双工 SerDes),0 时退化 datapath-only(fixture 绕过,对称 RX guard)。PhyLink per-edge 序列化保留并共存(§物理链路模型,零改动):chip 出口吞吐 binding = per-LG cap,PhyLink edge 不 double-限吞吐。(1.6.1 实施修正:初版拟撤 PhyLink chip 出口序列化以避免 double-serialize,验证证明撤 PhyLink crash single-switch 425→21,改为共存——per-LG binding 已使 busbw ≤ 400,PhyLink edge 非 throughput-binding,仅 latency 略增,见 ISSUE-033)。
RX 侧设计
PSN 校验与三种结果
RX 为每个 (src_chip, lg_id, qp_id) 维护 expected_psn (EPSN)——每个发送端 LG 在 RX 端有自己独立的保序窗口,跨 LG 不互相校验。收包时有三种结果:
| 条件 | 结果 | 行为 |
|---|---|---|
| psn == EPSN | 接受 | EPSN++,入 ACK MERGE 队列,返还 credit,可选 CNP |
| psn > EPSN(环形半区判定) | PSN 间隙 | 生成 NAK,返还 credit |
| psn < EPSN(环形半区判定) | 重复包 | 静默丢弃,返还 credit |
@tbl-spec-rclink-07 PSN 校验与三种结果:条件,结果
关键设计决策:三条路径都返还 credit。无论 PSN 校验结果如何,包已经消耗了物理缓冲空间,必须返还 credit 以维持流控平衡。如果 NAK 或重复包不返还 credit,长时间的重传场景会导致 credit 泄漏,最终死锁。
下图展示 RX 收包的完整处理流程,包括 PSN 校验的三条路径(正序、NAK、重复):
FACK(Fast ACK)
零字节包(tcredit)绕过 ACK MERGE,立即生成 ACK。零字节包不占 CBFC credit(payload=0 时不占用 RX 数据缓冲,既不消耗也无返还)。设计目的:tcredit 是控制面握手消息,延迟敏感,不应等待 ACK 汇聚周期。
ACK MERGE 汇聚
需求驱动调度:不使用固定周期轮询,而是由收包事件触发。poll_scheduled 标志防止重复调度——只有在新包到达且无 pending poll 时才调度 AckMergePoll 事件(延迟 POLL_CYCLE_NS = 4ns)。
累积 ACK 生成:RX 跟踪 max_contiguous_psn(最后一个连续 PSN 的下一个值)。AckMergePoll 触发时,如果 pending_count > 0,生成一个累积 ACK,其 ack_psn = max_contiguous_psn,确认所有 PSN < ack_psn 的包。
MERGE_DEPTH(默认 64):单次 poll 最多合并的包数。超过此数时下次 poll 继续处理。
ECN 检测与 CNP 生成
收到 ecn_marked == true 的包时(PSN 校验通过后),RX 检查 CNP 聚合窗口:
- Per-(src_chip, qp_id) 维护 last_cnp_ns
- 若 now - last_cnp_ns >= CNP_INTERVAL_NS(默认 2500ns),生成 CnpReceived 事件,更新 last_cnp_ns
- 否则忽略(窗口内抑制)
- 零字节包(FACK/tcredit)即使 ECN 标记也不生成 CNP
[NEEDS CLARIFICATION: CNP 聚合窗口 spec 正文采用 2500ns,设计文档为 50000ns,两值差 20×,待确认权威默认值]
CNP 作为 64B 小包,沿反向路由(复用 ACK 路径)经 RSP VC 传回发端。
credit 返还
收包后延迟 CREDIT_RETURN_DELAY_NS(默认 1ns)生成 CreditReturn 事件。返还量使用与 TX 消耗相同的公式:
$$\begin{equation} C_{\text{return}} = \lceil (\text{payload\_bytes} + \text{pkt\_ovhd}) / \text{credit\_size} \rceil \label{eq:rc-credit-return} \end{equation}$$CreditReturn 事件通过物理链路反向传输,但绕过序列化队列,仅经历传播延迟(见 §物理链路模型)。
芯片级聚合接收 cap
概念:RX 端镜像 TX 侧的芯片级聚合吞吐约束(见 §芯片级聚合发送 cap)。TX 侧每个 LG 的发包受 MAC credit 按 SerDes 线速 line_rate_per_lg 串行化释放;RX 侧对称——每个 LG 的收包同样按 line_rate_per_lg 串行化,N 个 LG 并行接收,芯片级聚合接收上限 = num_link_groups × line_rate_per_lg(SG2262:8 × 50 = 400 GB/s,与 TX 聚合上限相等,因为收发共用同一组全双工 SerDes)。
为什么需要:缺此约束时,高 radix 拓扑下单个芯片可同时从多个邻居接收,接收聚合带宽不受任何物理上限约束——与 TX 侧的芯片级 cap 不对称。流量集中(skewed)场景下,热点芯片的接收聚合会突破物理 SerDes 上限,使高 chip_radix 拓扑在仿真中获得不真实的接收带宽优势。
per-LG 并行接收串行化:收到的数据包(payload_bytes > 0)按 ITLV hash 落到对应 LG 的接收路径(与 TX 分发同一 hash 函数,与 src/dst 无关),每个 LG 维护独立的接收串行化时间线。单包接收串行化延迟:
每个 LG 的接收时间线按 busy 语义推进(与物理链路 eq:rc-link-delay 同构):到达时刻 now 的包,其有效接收完成时刻 = max(now, lg_busy) + T_rx_serialize,并据此更新该 LG 的 lg_busy。芯片级聚合接收带宽因此自然受限为 N 个 LG 串行化速率之和:
控制包绕过:payload_bytes == 0 的控制包(FACK、累积 ACK、NAK、CNP、CreditReturn)不计入芯片级数据接收 cap,也不经过 per-LG REQ 数据接收串行化。它们各自按既有物理链路模型处理:累积 ACK / NAK / CNP 走 RSP VC,按 §三层链路使用模型 经 RSP VC 序列化(与 REQ 数据队列独立,互不排队);CreditReturn 是 MAC 层信号,仅经历传播延迟(见 §CreditReturn 免序列化)。本节芯片级接收 cap 只约束 REQ 数据通道(payload > 0);控制包在独立的 RSP VC / MAC 信令通路处理,不占用 RX 数据接收带宽。
关键性质(镜像 §芯片级聚合发送 cap):
- N 源 incast:多个 src 的流量按 hash 散布到 N 个 LG 接收路径,聚合接收上限 = N × line_rate;当 hash 把流量集中到单个 LG 时,该 LG 成为接收瓶颈(在收发共用同一 ITLV hash 前提下,真实反映 SerDes 端口的负载分布而非假设完美均衡;该前提破坏时的偏差见 §局限)
- 单流:通过 segment 级 ITLV 散布到多 LG,单流也能用满聚合接收带宽
- N=1 退化为单 LG,接收串行化在单实例聚合
与 DCQCN / CBFC 流控的关系:RX 聚合 cap 是独立于拥塞控制的物理接收约束,与现有机制作用维度正交:
| 机制 | 约束对象 | 触发条件 |
|---|---|---|
| DCQCN | TX 单流(per dst+qp)发包节奏 | 交换机 buffer 拥塞标记 ECN |
| CBFC credit | TX 在途(in-flight)buffer 占用 | credit 耗尽 |
| RX 聚合 cap | 芯片级数据接收聚合带宽 | 始终生效(物理上限) |
@tbl-spec-rclink-rxcap-flowctrl RX 聚合 cap 与 DCQCN/CBFC 的维度区分
RX cap 推后包的接收完成时刻,进而推后该包的 CreditReturn 调度,使 credit 回流变慢,经 CBFC 对 TX 形成间接背压。这是物理因果(接收慢导致 credit 慢),不是与 DCQCN 的双重降速:二者约束不同的物理瓶颈(RX 入口聚合带宽 vs 路径中段交换机 buffer)。incast 下各源未必触发 ECN(各路径 buffer 未超阈值)却仍可聚合突破芯片接收上限——这正是 RX cap 要拦的、DCQCN 拦不到的维度。两者同时作用同一 TX 流时,叠加结果取更紧约束,符合真实硬件。
避免重复约束:业界 cycle-accurate 工具让聚合上限涌现于 per-port 串行化 + 共享仲裁,而非在其上叠加独立限速器。本模型的芯片级 cap 同样是 N 个 per-LG 串行化路径的自然求和,不是在 per-LG 串行化之外再设一个芯片级限速闸——聚合上限 num_link_groups × line_rate_per_lg 是 per-LG 串行化的数学结果,不重复约束。显式写出该上限是为对齐物理 NIC line-rate 语义并作为验收基准。业界对照见附录 A。
Go-Back-N 重传
NAK 触发
RX 检测到 PSN 间隙时生成 NAK。NAK 携带 ack_psn = EPSN(最后一个连续确认的 PSN 的下一个值),沿反向路由传回 TX。
TX 处理 NAK
- 检查重传计数是否超过 MAX_RETRY(默认 15),超过则标记错误
- 先做累积 ACK:释放 PSN < ack_psn 的所有 WaitAck Slot(这些包已被确认,不需要重传)
- 收集该 (dst, qp_id) 所有剩余的 WaitAck Slot
- 环形排序:按
psn.wrapping_sub(ack_psn) & PSN_MASK排序,正确处理 12-bit PSN wrap-around - 按 PSN 逆序 push_front 到 VC 队列头部,使最小 PSN 在队首(优先重传)
- 所有回退的 Slot 状态:WaitAck → WaitGrant
- 重传计数 +1
下图展示 Go-Back-N 重传的完整处理流程:
NAK 重传时序示例(PSN 空间 [5,6,7,8,9], NAK ack_psn=7):
Slot 状态 (NAK 前):
PSN 5: WaitAck ← PSN < 7, 已确认
PSN 6: WaitAck ← PSN < 7, 已确认
PSN 7: WaitAck ← 需重传
PSN 8: WaitAck ← 需重传
PSN 9: WaitAck ← 需重传
处理步骤:
1. 累积 ACK: 释放 PSN 5, 6 (Empty)
2. 收集: [PSN 7, 8, 9]
3. 环形排序: wrapping_sub(7,7)=0, wrapping_sub(8,7)=1, wrapping_sub(9,7)=2
4. 逆序 push_front: 先 9, 再 8, 再 7 → 队首 = PSN 7
5. 状态: PSN 7,8,9 全部 WaitAck → WaitGrant
超时重传
WaitAck 超过 RETRY_TIMEOUT_NS(默认 50000ns = 50us)未收到 ACK,视同 NAK 处理。超时重传使用 min_waitack_psn 作为基准 PSN(因为没有接收方反馈),对该 (dst, qp_id) 的所有 WaitAck Slot 执行 Go-Back-N。
物理链路模型
REQ/RSP 双队列
每条物理链路维护两个独立的 busy_until 时间戳:
| 队列 | 用途 | 流量类型 |
|---|---|---|
| REQ VC (busy_until_ns) | 数据包序列化 | SegmentInfo payload(从 TX 发往 RX) |
| RSP VC (busy_until_ns_rsp) | ACK/NAK/CNP 序列化 | 确认和控制包(从 RX 传回 TX) |
@tbl-spec-rclink-08 REQ/RSP 双队列:队列,用途
这模拟硬件中 REQ 和 RSP VC 的独立数据通路(默认权重 8:8 WRR)。ACK 包永远不会排在数据包后面等待,确保确认路径的低延迟。
每个队列的延迟公式相同:
$$\begin{equation} T = \max(0, \text{busy\_until} - \text{now}) + \frac{\text{wire\_bytes}}{\text{bandwidth}} + \text{base\_latency\_ns} \label{eq:rc-link-delay} \end{equation}$$ISSUE-033 — 与 per-LG 发送 cap 共存:
eq:rc-link-delay的wire_bytes/bandwidthper-edge 序列化对所有 edge 生效(chip 出口 + switch 内部,PhyLink 零改动)。chip 出口吞吐由 §芯片级聚合发送 cap(per-LG MAC credit,binding)与本 per-edge 序列化共同约束:binding = per-LG(50/LG < edge 400),PhyLink edge 在多 edge 下不 binding、single edge 下与 per-LG 共同 400,不 double-限吞吐(busbw ≤ 400),仅 latency 略增。(1.6.1 实施修正:初版拟对 chip 出口撤 per-edge 序列化以避免 double-serialize,验证证明撤会 crash single-switch 425→21,改为保留共存,见 ISSUE-033)
CreditReturn 免序列化
CreditReturn 事件仅经历传播延迟(base_latency_ns),不经过任何序列化队列。设计依据:硬件中 credit 返还是 MAC 层信号(类似 PCIe/CXL/UCIe 的 credit flow),在物理层有独立的信令通路,不占用数据带宽。
三层链路使用模型
| 层级 | 适用流量 | 延迟模型 |
|---|---|---|
| REQ VC | 数据包 | 排队 + 序列化 + 传播 |
| RSP VC | ACK/NAK/CNP | 排队 + 序列化 + 传播(独立队列) |
| MAC 控制 | CreditReturn | 仅传播延迟(无序列化) |
@tbl-spec-rclink-09 三层链路使用模型:层级,适用流量
Relay 芯片处理
多跳路径中的中间芯片(relay)不经过 RC Link 处理。包到达 relay 芯片后,直接查路由表转发到下一跳物理链路,不做 PSN 校验、ACK MERGE 等处理。只有最终目标芯片才经过完整的 RX 处理流程。
报头开销估算
仿真使用固定 header_overhead(默认 50B),对应 Standard 报文格式。各格式的实际开销:
| 报文格式 | 组成 | 估算开销 |
|---|---|---|
| Standard | MAC(14B) + IP(20B) + UDP(8B) + RH(8B) + 可选ICRC(4B) | ~50-54B |
| AFH_GEN1 | 压缩头 + 可选 TC 域 | ~22-30B |
| AFH_GEN2_16b | 16-bit 地址压缩 + Key_words 标志位 | ~16-20B |
| AFH_Lite | Traffic Class 区分 TYPE1/TYPE2 | 最小 |
@tbl-spec-rclink-10 报头开销估算:报文格式,组成
有效带宽受报头开销影响:
$$\begin{equation} BW_{\text{eff}} = BW_{\text{link}} \times \frac{\text{payload}}{\text{payload} + \text{header\_overhead} + \text{FEC\_overhead}} \label{eq:rc-effective-bandwidth} \end{equation}$$默认配置下(payload=1344B, header_overhead=50B),有效带宽约为 payload/(payload+50) = 96.4% 的链路带宽。FEC 开销当前不建模(见 §局限与后续工作)。
序列保证规则
| 场景 | 顺序保证 | 说明 |
|---|---|---|
| 同 (dst, qp_id) TYPE1 | 有 | PSN 顺序发送 + Go-Back-N 保证按序交付 |
| 同 VC 同 DA | 有 | VC 内 FIFO |
| 不同 DA | 无 | 可能经过不同路径,延迟不同 |
| 不同 VC | 无 | VC 间无排序约束 |
| 读写同地址 | 无 | 需上层 fence/barrier 保证 |
@tbl-spec-rclink-11 序列保证规则:场景,顺序保证
DCQCN 拥塞控制
DCQCN 替换了原有的固定速率窗口 (RateCtrl),提供动态拥塞响应能力。
整体回路
Switch ECN RED 标记 → RX CNP 生成(聚合窗口) → TX 降速(乘性减)→ TX 速率恢复(快速恢复 + 加性增)
三条路径:
- Forward Path:数据包经 Switch 时被 ECN 概率标记
- Feedback Path:RX 检测 ECN 标记,生成 CNP 反馈给 TX
- Recovery Path:TX 无 CNP 时通过 ByteCounter + TimeTimer 逐步恢复速率
下图展示 DCQCN 的完整事件回路,涵盖拥塞检测、反馈和速率恢复三条路径:
DCQCN 速率控制在以下三个状态间转换:
ECN RED 概率标记 (Switch 侧)
DCQCN 的 Forward Path 依赖 Switch 对经过的数据包进行 ECN 概率标记。标记概率基于出口缓冲的利用率 (utilization):
$$\begin{equation} P_{\text{ecn}}(\text{util}) = \begin{cases} 0 & \text{util} < K_{\min} \\ \dfrac{\text{util} - K_{\min}}{K_{\max} - K_{\min}} & K_{\min} \leq \text{util} < K_{\max} \\ 1.0 & \text{util} \geq K_{\max} \end{cases} \label{eq:rc-ecn-red-probability} \end{equation}$$其中:
- $K_{\min}$:ECN 标记开始的利用率阈值,默认 0.3(RoCEv2 典型值)
- $K_{\max}$:ECN 必然标记的利用率阈值,默认 0.8
- $\text{util}$:Switch 出口缓冲当前利用率 = 已用容量 / 总容量
伪随机数生成使用 Xorshift64 算法(确定性,可复现)。ECN 标记写入包的 ecn_marked 字段,RX 侧据此决定是否生成 CNP。
DCQCN 状态机 (per-QP)
Per-(dst, qp_id) 维护 DcqcnState:
NORMAL (rate = line_rate, 无 Timer)
↓ 收到 CNP
CONGESTED (rate < line_rate, ByteTimer + TimeTimer 并行)
├─ FastRecovery (stage <= 5): rate += (target - rate) / 2
└─ AdditiveIncrease (stage > 5): rate += line_rate / additive_increase_factor
↓ rate >= line_rate
RECOVERED → NORMAL (Timer 停止)
↑ 收到 CNP → 回到 CONGESTED
CNP 到达处理 (on_cnp)
- Alpha EMA 更新:$\alpha \leftarrow (1 - g) \cdot \alpha + g$
- 保存目标速率:$R_T \leftarrow R_C$
- 乘性减:$R_C \leftarrow R_C \cdot (1 - \alpha / 2)$
- 速率下限:$R_C \leftarrow \max(R_C, R_{\min})$
- 重置 byte_counter 和 recovery_stage_count
- 若 TimeTimer 未 arm,arm 之
速率恢复 (rate_increase)
两个触发源并行工作:
| 触发源 | 条件 | 行为 |
|---|---|---|
| ByteCounter | 累积发送 >= byte_threshold (150KB) | rate_increase() + 重置 counter |
| TimeTimer | 每 timer_interval_ns (55us) | alpha 衰减:$\alpha \leftarrow \alpha \cdot (1-g)$,然后 rate_increase() |
@tbl-spec-rclink-12 速率恢复 (rate_increase):触发源,条件
rate_increase() 两阶段恢复:
$$\begin{equation} R_C \leftarrow \begin{cases} R_C + (R_T - R_C) / 2 & \text{stage} \leq \text{fast\_recovery\_stages} \\ R_C + R_{\text{line}} / \text{additive\_increase\_factor} & \text{stage} > \text{fast\_recovery\_stages} \end{cases} \label{eq:rc-dcqcn-rate-increase} \end{equation}$$ $$\begin{equation} R_C \leftarrow \min(R_C, R_{\text{line}}) \label{eq:rc-dcqcn-rate-cap} \end{equation}$$recovery_stage_count++ 每次调用递增。
Timer 生命周期:timer_armed 标志防止重复调度。当 rate >= line_rate 时 Timer 停止(不再 reschedule)。
TX 速率限制 (pacing)
Rate-based pacing 而非 window-based:
$$\begin{equation} T_{\text{min\_interval}} = \frac{\text{header\_overhead} + \text{max\_payload}}{\text{current\_rate\_bytes\_per\_ns}} \label{eq:rc-dcqcn-pacing} \end{equation}$$仲裁时检查 now >= last_send_ns + min_interval,不满足则 rate-block;该 dst,qp_id 的最早可发时刻 (last_send_ns + min_interval) 应通过 §Segment Dispatch 机制 的 next_t 路径精确 schedule,确保 pacing 阻塞解除时立即恢复仲裁,而非 polling 等候。
实施状态(v3.x):rate-block 精确 wake 当前未接入
feed_rc_link的next_t路径——21 拓扑 alltoallv 评估中 DCQCN 全程 dormant(见docs/issues/ISSUE-031/refactor-proposal.md跨拓扑诊断,21/21rate_block=0),incast / 高数据量场景需补;详见 ISSUE-031 Q-5。
单位约定:current_rate 内部单位为 bytes/ns(= GB/s)。C2C 链路带宽 bandwidth_gb_per_s 的单位即 GB/s(= bytes/ns),直接使用,无需除以 8。
诊断计数器
TX 维护诊断计数器用于瓶颈分析。完整计数器清单见附录 C。
备选方案
DCQCN vs 固定速率窗口
| 维度 | DCQCN (选定) | 固定速率窗口 (RateCtrl) |
|---|---|---|
| 拥塞响应 | 动态:根据 ECN 信号调整速率 | 无:固定 86KB/1000ns 上限 |
| 精度 | 能建模 incast 带宽下降和恢复 | 无法建模拥塞行为 |
| 复杂度 | 高:ECN + CNP + 状态机 + 双 Timer | 低:计数器 + 窗口重置 |
| 参数化 | 8 个可调参数 | 2 个参数 |
@tbl-spec-rclink-14 DCQCN vs 固定速率窗口:维度,DCQCN (选定)
选择理由:固定速率窗口无法建模网络拥塞的核心行为——有效带宽随负载变化。DCQCN 虽然复杂度高,但它是 RoCEv2 数据中心网络的标准拥塞控制算法,参数有 DCQCN 论文和工业实践支撑。
物理链路单队列 vs 双队列
| 维度 | REQ/RSP 双队列 (选定) | 单队列 |
|---|---|---|
| ACK 延迟 | ACK 不受数据包排队影响 | ACK 排在数据包后面 |
| 硬件保真度 | 匹配硬件 WRR 仲裁 | 过度简化 |
| 实现复杂度 | 两个 busy_until 跟踪 | 一个 |
@tbl-spec-rclink-15 物理链路单队列 vs 双队列:维度,REQ/RSP 双队列 (选定)
选择理由:大量数据包在途时,单队列会导致 ACK 延迟膨胀,进而影响 credit 返还和 Slot 释放,产生级联效应。双队列消除了这一失真。
DCQCN 两阶段恢复 vs 硬件旧版三阶段恢复
| 维度 | 两阶段 (选定) | 三阶段 (旧版硬件 DCQCN) |
|---|---|---|
| 阶段 | FastRecovery + AdditiveIncrease | FastRecovery + AdditiveIncrease + HyperIncrease |
| 降速公式 | $R_C \times (1 - \alpha/2)$ | $R_C \times (1 - \alpha / 2^{\text{alpha\_rate\_shift}+10})$ |
| 复杂度 | 低:2 个分支 | 高:3 个分支 + alpha_rate_shift 参数 |
| 参考来源 | DCQCN 论文原始算法 | 硬件定制扩展 |
@tbl-spec-rclink-16 DCQCN 两阶段恢复 vs 硬件旧版三阶段恢复:维度,两阶段 (选定)
选择理由:G5 仿真采用 DCQCN 论文的标准算法(2 阶段),不引入硬件旧版的 Hyper Increase 扩展。两阶段恢复已足够建模拥塞后的速率收敛行为。alpha_rate_shift 参数使降速更平缓,但增加了参数调优复杂度,仿真中直接使用 $\alpha/2$ 更透明。
VC 仲裁:加权 RR vs 硬件 Bank Mask 轮转
| 维度 | 加权 RR (选定) | Bank Mask 轮转 (硬件) |
|---|---|---|
| 调度语义 | 每个 VC 服务 weight 次后轮转 | 发包后按 qpid_msb 排除同 bank |
| 宏观公平性 | 等价 | 等价 |
| 微观包顺序 | 可能不同 | 硬件精确 |
| 实现复杂度 | 低 | 中(需维护 mask 集合) |
@tbl-spec-rclink-17 VC 仲裁:加权 RR vs 硬件 Bank Mask 轮转:维度,加权 RR (选定)
选择理由:仿真关注宏观带宽分配和拥塞行为,不依赖精确的单包调度顺序。两种机制在统计意义上等价——都确保各 bank 获得均等的发送机会。加权 RR 更通用,参数化也更直观。
RX 聚合 cap:per-LG 并行 vs chip 级单一队列 vs 无 cap
| 维度 | per-LG 并行 (选定) | chip 级单一队列 | 无 RX cap |
|---|---|---|---|
| 物理保真 | 镜像 8 个 SerDes RX 端口,捕捉 hash 碰撞热点 | 假设完美 LG 均衡,碰撞时高估接收 | 接收聚合可无上限突破物理 cap |
| 控制包 | payload=0 绕过(对齐 TX 侧 MAC 控制免序列化) | 易把控制包错计入数据带宽 | — |
| 聚合带宽正确性 | 饱和态 = N × line_rate | 饱和态 = N × line_rate(等价) | 失真(可达物理上限数倍) |
| 与 TX 对称性 | 与 TX per-LG MAC credit 对称 | 与 PhyLink per-edge 单 busy 形似但语义错配 | 无对称 |
| 业界参照 | BookSim / Merlin / RDMA per-port 并行 | 仅 ASTRA-sim analytical 单队列 | ASTRA-sim 纯 per-link(incast 虚高根因) |
@tbl-spec-rclink-rxcap-alt RX 聚合 cap 建模方案对比
选择理由:per-LG 并行接收与 TX 侧 per-LG MAC credit 对称,且与业界主流(per-port 并行接收)一致。chip 级单一队列在饱和态聚合带宽上与 per-LG 等价,但假设完美 LG 均衡(hash 碰撞时高估单芯片接收能力),且若不显式区分会把控制包错计入数据带宽——为实现简单牺牲了 SerDes 端口分布的真实性。"无 cap" 是 incast/skewed 流量下接收带宽失真的直接来源,否决。
非功能性需求
| 维度 | 本 spec 的考虑 |
|---|---|
| 性能 (Performance) | TX 聚合发包上限 = num_link_groups × line_rate_per_lg(SG2262 = 400 GB/s);RX 聚合接收同上限;单 frame 端到端 ≈ 178.9 ns(datapath 68 ns + PhyLink 110.9 ns);有效带宽默认配置约 96.4%(受 header_overhead 影响) |
| 可靠性 (Reliability) | Go-Back-N 端到端重传(MAX_RETRY=15);超时重传(RETRY_TIMEOUT_NS=50us);三条 PSN 校验路径都返还 credit 防 credit 泄漏死锁;relay 芯片不做中间重传,由端到端 Go-Back-N 覆盖 |
| 兼容性 (Compatibility) | N=1 退化为单 LG 模型,PSN/credit/Slot 状态在单实例聚合;qp_id 用硬件可见 {XPU_ID, BANK} 编码与硬件协议一致,软件改线程划分不影响 PSN 空间分配 |
| 可观测性 (Observability) | 按 LG 分行输出诊断计数器(diag_arb_tx_busy / diag_credit_block / diag_rate_block / diag_slot_full / diag_nak_* / diag_max_retry_hit),供瓶颈分析与验收检查 |
| 安全性 (Security) | 本 spec 模块在仿真器内部运行,不涉及鉴权 / 加密 / 多租户隔离(P_key 分区为非目标) |
局限与后续工作
局限(本设计的代价)
| 风险 / 局限 | 影响 | 缓解措施 |
|---|---|---|
| DCQCN 参数敏感性 | 不当参数导致速率震荡或恢复过慢 | 使用 DCQCN 论文推荐的默认值,提供诊断计数器验证 |
| CNP 聚合窗口过大 | 拥塞响应延迟增大 | 默认 2500ns(远小于 RTT) |
| 物理链路忽略 FEC 开销 | 有效带宽略高于实际 | 可通过 pkt_ovhd 参数修正 |
| Relay 芯片不做 RC Link 处理 | 多跳路径无中间节点可靠性保护 | 端到端 Go-Back-N 已覆盖,无需中间重传 |
| RX 聚合 cap 假设收发端 hash 分布一致 | 若 RX 端 LG 分流与 TX 不同,per-LG 热点估计有偏差 | 收发共用同一 ITLV hash 函数与同一组 SerDes,分布天然一致;偏差仅在 hash 实现不一致时出现,由 §ITLV 分发机制 的 hash 一致性要求覆盖 |
@tbl-spec-rclink-18 风险与缓解措施
.claude/rules/下的项目规则由iforge-spec-review在审核时整体核对。
后续工作(后续扩展方向)
| 方向 | 优先级 | 前置条件 |
|---|---|---|
| PFC 链路级流控 | 中 | 需要 Switch → Chip 反向 PAUSE 帧事件 |
| 多报文格式支持 | 低 | 需要 per-link 的 header_overhead 配置 |
| 动态 credit_uf_limit 调节 | 低 | 硬件仅 TYPE1 REQ 支持 |
| Per-port ECN(替代 per-buffer) | 中 | 需要 Switch 出口端口级缓冲跟踪 |
@tbl-spec-rclink-21 未来方向
验收标准
| 场景 | 指标 | 目标值 | 测试方法 |
|---|---|---|---|
| 无拥塞 2 芯片 P2P | 有效带宽 | >= 95% 线速 | 比较仿真吞吐与 link bandwidth |
| 4→1 incast 经 Switch | DCQCN 触发 | ECN 标记 + CNP 生成 + 速率下降 | 检查诊断计数器 diag_rate_block > 0 |
| incast 结束后 | 速率恢复 | 恢复到 line_rate | 检查 DcqcnState.current_rate == line_rate |
| CBFC credit 耗尽 | Slot 阻塞 | 包等待 CreditReturn 后继续 | 检查 diag_credit_block > 0 且最终完成 |
| Go-Back-N NAK | 重传正确 | NAK 后包按 PSN 顺序重传 | 检查 diag_nak_retransmit_total 和 PSN 连续性 |
| ACK MERGE | ACK 减少 | 单个 ACK 覆盖多包 | 比较 ACK 数量 << 数据包数量 |
| 高 radix incast 接收 cap | 单芯片数据接收聚合带宽 | <= num_link_groups × line_rate_per_lg | 任意拓扑跑流量集中 workload,测峰值单芯片接收聚合带宽不超物理上限 |
| 高 radix chip 发送 cap (G8) | 单芯片数据发送聚合带宽 | <= num_link_groups × line_rate_per_lg | 多 edge chip(cpb=8 板内 mesh / torus)同时发多 dst,测峰值单芯片发送聚合带宽不超物理上限(ISSUE-033 复现:fat-tree-k16 ECMP S1 tok=1024 chip0 TX <= 400,修前 700) |
| 控制包绕过数据接收 cap | 控制包接收延迟 | 不随 REQ 数据接收队列增长(CreditReturn 仅传播延迟;ACK/NAK/CNP 经独立 RSP VC) | 高接收负载下控制包(payload=0)延迟不随数据接收队列长度变化 |
@tbl-spec-rclink-19 验收标准
单元测试场景:
| 测试 | 输入 | 预期输出 |
|---|---|---|
| PSN 半区判定 | before(4090, 5) | true(跨 wrap) |
| PSN 半区判定 | before(5, 4090) | false |
| CBFC credit 消耗 | payload=1344B, ovhd=50B, credit_size=256B | ceil(1394/256) = 6 |
| DCQCN on_cnp | alpha=1.0, g=1/256, rate=50.0 bytes/ns | alpha=0.9961+0.0039=1.0, rate=50*(1-0.5)=25.0 bytes/ns |
| ECN RED 概率 | util=0.55, kmin=0.3, kmax=0.8 | p = (0.55-0.3)/(0.8-0.3) = 0.5 |
| ECN RED 边界 | util=0.2, kmin=0.3 | p = 0 (低于阈值) |
| ECN RED 边界 | util=0.9, kmax=0.8 | p = 1.0 (超过上限) |
| DCQCN rate_increase (FastRecovery) | stage=1, R_C=25.0, R_T=50.0 | R_C = 25.0 + (50.0-25.0)/2 = 37.5 |
| DCQCN rate_increase (AdditiveIncrease) | stage=6, R_C=45.0, R_line=50.0, factor=200 | R_C = 45.0 + 50.0/200 = 45.25 |
| Go-Back-N 环形排序 | PSN=[9,7,8], ack_psn=7 | 排序后 [7,8,9],队首=7 |
| RX 单 LG 接收串行化 | payload=1344B, ovhd=50B, line_rate=50B/ns,同一 LG 连收 2 包 | 第 2 包接收完成 = 2 × (1394/50) ≈ 55.8 ns(串行,不并行) |
| RX 芯片级聚合 cap | 8 LG, line_rate=50B/ns, 8 源各发满 | 芯片聚合接收 = 8 × 50 = 400 B/ns,不超 |
| RX 控制包绕过 | payload=0 控制包在高接收负载下到达 | 不进 per-LG REQ 接收串行化(延迟不随 REQ 数据队列增长) |
| TX 单 LG 发送串行化 (G8) | frame_wire=1394B, line_rate=50B/ns,同一 LG 连发 2 frame | 第 2 frame 发送完成 = 2 × (1394/50) ≈ 55.8 ns(串行,不并行) |
| TX 芯片级聚合 cap (G8) | 8 LG, line_rate=50B/ns,多 edge chip 同时发多 dst | 芯片聚合发送 = 8 × 50 = 400 B/ns,不超(cpb=8 多 edge 不放大) |
| TX 控制包绕过 (G8) | payload=0 控制包在高发送负载下 | 不占发送数据 cap |
@tbl-spec-rclink-20 Success Criteria:测试,输入
附录
附录 A:业界调研
Per-port 独立状态机
| 协议/IP | 多端口 RC 状态分布 | 与本设计对应 |
|---|---|---|
| InfiniBand dual-port HCA | 每 port 独立 RC(独立 PSN/QP retransmit context) | 同 |
| Mellanox ConnectX dual-port | 每 port 独立 reliable transport state | 同 |
| NVLink multi-sub-link (NVL3/4) | 每 sub-link 独立 retransmission context | 同 |
| CXL multi-stack Type-3 | 每 stack 独立 ARQ | 同 |
@tbl-spec-rclink-05 多 Link Group 并行模型:协议/IP,多端口 RC 状态分布
业界压倒性走 per-port/per-LG 独立物理层状态机模式(control plane 共享、data plane 多实例)。本模型与之对齐。
Multi-link 分发策略(均用 hash 不用 round-robin)
| 场景 | 分发函数 | 输入字段 |
|---|---|---|
| ECMP(IP multipath) | CRC32 / Toeplitz / FNV | 5-tuple(src/dst IP + protocol + src/dst port) |
| RSS(NIC RX 分流到多核) | Toeplitz | 4/5-tuple |
| RoCE flow steering | hash | QP id + flow key |
| NVLink lane balancing | byte-stripe(本质是 packet-level hash by addr) | 物理地址 |
| PCIe multi-lane | byte-stripe | 物理地址 |
| DASH disk striping | hash-based stripe | block id |
@tbl-spec-rclink-itlv-industry 业界 multi-link 分发函数选择
业界几十年实践的共识:多源 + 时间结构化 workload 下必须用 hash,round-robin 仅在单源、无时间结构的场景下安全。
接收端聚合带宽建模对照
| 仿真器 | 接收端聚合建模 | 控制包处理 |
|---|---|---|
| SST/Merlin | per-port PortControl + 独立 xbar_bw,聚合上限涌现于 per-port 串行化 + crossbar 仲裁 | credit / CongestionEvent 独立 event,不占数据 buffer |
| BookSim 2.0 | per-subnet 并行 ejection,每路每 cycle 取 1 flit | credit 独立路径 |
| ASTRA-sim(analytical) | 纯 per-link 单队列串行,无 node 级聚合 cap | 不建模控制包 |
| 真实 RDMA NIC(RoCEv2/IB) | 接收上限 = NIC 单 ingress link line-rate;incast collapse 即超此上限 | CNP / PFC 独立处理 |
@tbl-spec-rclink-rxcap-industry 业界接收端聚合带宽建模对照
本模型按 per-LG 并行接收串行化得到芯片级聚合 cap,与 BookSim(per-subnet 并行)、Merlin(per-port 并行)、真实 RDMA(per-port queue)的 per-port 并行接收结构一致;ASTRA-sim 的纯 per-link 单队列模型(无 node 级聚合约束)正是"高 radix incast 接收聚合虚高"的同款结构性缺陷,本设计否决该路线。
外部引用
- SST/Merlin:Merlin Element Library Deep Dive (Sandia SAND2018-3859PE);
linkControl.cc - BookSim 2.0:User's Guide;source
- ASTRA-sim:
congestion_aware/Link.h;Won et al., ASTRA-sim2.0, arXiv:2303.14006 - RDMA incast / DCQCN:Zhu et al., "Congestion Control for Large-Scale RDMA Deployments", SIGCOMM 2015(ns3-rdma);Chen et al., "Understanding TCP Incast Throughput Collapse in Datacenter Networks", WREN 2009
附录 B:实现说明
记录 spec 与实际实现的偏差事实:
- [2026-04-21] DCQCN 已完整实现(非"预留"),包含 ECN RED、CNP 生成/聚合、DcqcnState 状态机、ByteCounter + TimeTimer 恢复。
- [2026-04-21] 物理链路 REQ/RSP 双队列已实现。CreditReturn 免序列化已实现。
- [2026-04-21] CNP 聚合窗口默认值在代码中为 2500ns,DCQCN 设计文档中为 50000ns (50us)。两值不一致,待确认。
RcLinkTx::on_pack_done在代码实现中命名为on_tx_done。
附录 C:完整接口签名 / 数据结构 / 参数
与单 LG 设计的接口改造点
§详细设计 各章节规则作用域为单 LG 实例内部。多 LG 改造在以下接口加 lg_id 维度:
RcLinkTx实例化 N 份,每份持有独立 (slots, next_psn, vc_pending, credits, retry_counter, dcqcn_states, tx_busy)submit_packet(lg_id, dst, payload, vc_id, txn_id, qp_id)— PAXI Core 在 segment 提交时确定 lg_idtry_arbitrate(lg_id, now)— 在指定 LG 实例内做 VC 仲裁process_ack(lg_id, from_chip, qp_id, ack_psn)— ACK 路由到对应 LGprocess_nak(lg_id, from_chip, qp_id, ack_psn)— NAK 触发 Go-Back-N 限定在该 LGon_credit_return(lg_id, dst, vc_id, count)— Credit 返还到对应 LGEvent::RcPackDone { ..., lg_id }— 事件携带 lg_idEvent::C2CLinkDone { ..., lg_id }— RX 路由到对应 (src, lg_id, qp_id) EPSNEvent::CreditReturn { ..., lg_id }— Credit 反向通道也带 lg_id
RcLinkTx 公共接口
1.2.0 起
RcLinkTx实例化为 N 份(每个 LG 一份,隶属于一个芯片的 PAXIBridge)。所有方法的状态作用域是单 LG 实例——对应(chip_id, lg_id)元组。lg_id 不出现在方法签名中,因为它已隐含在&self。事件契约(Event)中需要显式携带 lg_id,让事件接收方路由到正确实例。
impl RcLinkTx {
/// 创建一个 LG 实例。chip_id 标识所属芯片,lg_id 标识在该芯片中的 LG 序号。
pub fn new(chip_id: u32, lg_id: u8, config: RcLinkTxConfig) -> Self;
/// 提交单个包到本 LG。分配 Slot + PSN(per-(dst, qp_id) 在本 LG 内独立计数),入 VC pending 队列。
/// 返回 true = 已分配 Slot;false = Slot 耗尽,调用方应排队。
pub fn submit_packet(
&mut self, dst: u32, payload_bytes: u32, vc_id: u32, txn_id: u64, qp_id: u16,
) -> bool;
/// 在本 LG 实例内做 VC 加权 RR 仲裁。成功时返回 (event_time, RcPackDone {..., lg_id: self.lg_id})。
pub fn try_arbitrate(&mut self, now_ns: f64) -> Option<(f64, Event)>;
/// 打包完成回调(事件中的 lg_id 已路由到本实例)。释放本 LG 的 TX datapath,尝试再次仲裁。
/// (代码实现命名为 on_tx_done)
pub fn on_pack_done(&mut self, now_ns: f64) -> Option<(f64, Event)>;
/// 累积 ACK:释放本 LG 内 PSN < ack_psn 的所有 WaitAck Slot。
/// 调用方负责按 (lg_id) 路由到对应实例。
pub fn process_ack(
&mut self, from_chip: u32, qp_id: u16, ack_psn: u16,
) -> Vec<SlotRelease>;
/// Go-Back-N:将本 LG 内 WaitAck Slot 回退到 WaitGrant 重传。
/// 返回 Err 当 retry_counter >= MAX_RETRY。
/// NAK 仅影响本 LG 的流,不波及其它 LG。
pub fn process_nak(
&mut self, from_chip: u32, qp_id: u16, ack_psn: u16,
) -> Result<(), &'static str>;
/// CNP 到达:对本 LG 内的 (from_chip, qp_id) 执行 DCQCN 降速。
pub fn on_cnp(&mut self, from_chip: u32, qp_id: u16) -> bool;
/// DCQCN TimeTimer 到期。
pub fn on_dcqcn_timer(&mut self, from_chip: u32, qp_id: u16) -> bool;
/// Credit 返还:增加本 LG 与对端 RX 在 (dst, vc_id) 上的 credit 账本。
pub fn on_credit_return(&mut self, dst: u32, vc_id: u32, count: u32);
}
RcLinkRx 公共接口
impl RcLinkRx {
/// 收包处理。PSN 校验 + credit 返还 + ECN/CNP + ACK MERGE。
/// 返回 RxResult { accepted, events }。
pub fn receive_packet(
&mut self,
src_chip: u32, qp_id: u16, psn: u16,
payload_bytes: u32, vc_id: u32, txn_id: u64,
now_ns: f64, ecn_marked: bool,
) -> RxResult;
/// ACK MERGE poll:生成累积 ACK 事件。
pub fn ack_merge_poll(
&mut self, src_chip: u32, qp_id: u16, now_ns: f64,
) -> Vec<(f64, Event)>;
}
调用关系
PAXIBridge.feed_rc_link()
├─> PAXICore.select_lg(segment) → lg_id ← ITLV: segment 级 LG 选择 (hash / RR / least_busy)
└─> rc_links[lg_id].submit_packet()
└─> rc_links[lg_id].try_arbitrate() ──> Event::RcPackDone { ..., lg_id }
└─> rc_links[lg_id].on_pack_done() ──> try_arbitrate() (链式)
Event::C2CLinkDone { ..., lg_id } ← 物理链路传输完成,携带 lg_id
└─> rc_links_rx[lg_id].receive_packet() ← RX 路由到对应 LG 实例
└─> 按 (src_chip, lg_id, qp_id) 校验 PSN → 生成 ACK/NAK/CNP
Event::AckArrived { ..., lg_id }
└─> rc_links[lg_id].process_ack() ← ACK 路由回发送侧对应 LG
Event::NakArrived { ..., lg_id }
└─> rc_links[lg_id].process_nak() ← NAK 触发的 Go-Back-N 限定在该 LG
Event::CreditReturn { ..., lg_id }
└─> rc_links[lg_id].on_credit_return() ← Credit 反向通道也带 lg_id
Event::C2CLinkDone (数据包到达)
└─> RcLinkRx.receive_packet()
├─> Event::CreditReturn (延迟 1ns)
├─> Event::AckMergePoll (延迟 4ns)
├─> Event::CnpReceived (条件: ECN + 窗口外)
└─> Event::AckArrived (FACK: 立即)
Event::AckMergePoll
└─> RcLinkRx.ack_merge_poll()
└─> Event::AckArrived (累积 ACK)
Event::AckArrived
└─> RcLinkTx.process_ack() ──> SlotRelease -> PAXIBridge.on_ack()
Event::NakArrived
└─> RcLinkTx.process_nak() ──> Slot 回退 + try_arbitrate()
Event::CnpReceived
└─> RcLinkTx.on_cnp() ──> DcqcnState.on_cnp()
└─> arm DcqcnTimeTimer (如需)
Event::DcqcnTimeTimer
└─> RcLinkTx.on_dcqcn_timer() ──> reschedule (如 rate < line_rate)
诊断计数器
| 计数器 | 含义 |
|---|---|
| diag_arb_calls | 单 LG 仲裁调用总次数 |
| diag_arb_tx_busy | 单 LG 因自身 datapath 忙而跳过的次数(per-LG 实例视角;DIAG 输出按 LG 分行) |
| diag_credit_block | 因 CBFC credit 不足而阻塞的次数 |
| diag_rate_block | 因 DCQCN 速率限制而阻塞的次数 |
| diag_slot_full | 因 Slot 耗尽而阻塞的次数 |
| diag_nak_processed | 处理的 NAK 数量 |
| diag_max_retry_hit | 达到最大重传次数的流数量 |
| diag_nak_retransmit_total | NAK 导致的重传包总数 |
@tbl-spec-rclink-13 诊断计数器:计数器,含义
多 Link Group 参数与解耦
| 参数 | 含义 | 默认值 |
|---|---|---|
num_link_groups | LG 实例数 | 8(SG2262) |
datapath_bytes | 单 LG MAC 处理位宽(决定 pack_delay) | 64B (512-bit) |
line_rate_per_lg_bytes_per_ns | 单 LG SerDes 线速(决定 MAC credit 释放间隔和 DCQCN 速率上限) | 50 (= 400 GB/s ÷ 8 LG) |
@tbl-spec-rclink-06 多 Link Group 并行模型 参数
为什么 datapath 和 line_rate 必须独立配置:硬件中 NoC 端处理位宽 (datapath) 通常宽于 SerDes 串行后的线速 (line_rate)。MAC datapath 64B/ns @1GHz = 512 Gbps,但 SerDes 经 PAM4 编码 + FEC 开销后单 LG 实际线速 50B/ns ≈ 400 Gbps。
TX 参数
| 参数 | 含义 | 默认值 |
|---|---|---|
| TYPE1_OST | Slot 池大小 | 512 |
| HEADER_OVERHEAD | 每包头部开销 | 50B |
| MAX_PAYLOAD | 最大包负载 | 1344B |
| CREDIT_SIZE | CBFC 信用粒度 | 256B |
| CREDIT_UF_LIMIT | 信用下限保留 | 1 |
| INITIAL_CREDIT | 初始 credit 数量 | 1024 |
| MAX_RETRY | Go-Back-N 最大重传次数 | 15 |
| RETRY_TIMEOUT_NS | 重传超时 | 50000 |
| PACK_DATAPATH_WIDTH | 单 LG 打包 datapath 宽度 | 64B (512-bit) |
| NUM_LINK_GROUPS | 物理 LG 实例数(TX 数据层并行度) | 8 (SG2262 默认) |
| LINE_RATE_PER_LG_BYTES_PER_NS | 单 LG SerDes 线速 (B/ns) | 50 (= 400 GB/s ÷ 8 LG) |
@tbl-spec-rclink-22 TX 参数
RX 参数
| 参数 | 含义 | 默认值 |
|---|---|---|
| MERGE_DEPTH | ACK MERGE 单次最大合并数 | 64 |
| POLL_CYCLE_NS | ACK MERGE 轮询延迟 | 4.0 |
| CREDIT_RETURN_DELAY_NS | credit 返还延迟 | 1.0 |
| CNP_INTERVAL_NS | CNP 聚合窗口 | 2500 |
@tbl-spec-rclink-23 RX 参数
DCQCN 参数
| 参数 | 含义 | 默认值 | 来源 |
|---|---|---|---|
| initial_alpha | 初始 alpha 值 | 1.0 | DCQCN 论文 |
| g | alpha EMA 平滑因子 | 1/256 | DCQCN 论文 |
| byte_threshold | ByteCounter 触发阈值 | 150KB | DCQCN 论文 (F) |
| timer_interval_ns | TimeTimer 周期 | 55000 | DCQCN 论文 (T) |
| min_rate_bytes_per_ns | 速率下限 | 1.0 bytes/ns (= 1.0 GB/s = 8 Gbps) | 防止降到 0 |
| fast_recovery_stages | 快速恢复阶段数 | 5 | DCQCN 论文 |
| additive_increase_factor | 加性增因子 | 200 | DCQCN 论文 |
@tbl-spec-rclink-24 DCQCN 参数
ECN RED 参数 (Switch 侧)
| 参数 | 含义 | 默认值 | 来源 |
|---|---|---|---|
| ecn_kmin | ECN 标记起始利用率 | 0.3 | RoCEv2 典型值 |
| ecn_kmax | ECN 必然标记利用率 | 0.8 | RoCEv2 典型值 |
@tbl-spec-rclink-25 ECN RED 参数 (Switch 侧) 参数