跳到主要内容

07 - 芯片间互联: PAXI Link + L2 Switch 建模

本文档设计 PAXI 链路模型和 L2 交换机模型在 G5 指令级仿真器中的实现方案。

基于:

  • docs/design/PAXI/PAXI_MODELING_ANALYSIS.md (PAXI + RC Link 行为分析)
  • docs/design/switch-modeling/SWITCH_BEHAVIOR_ANALYSIS.md (交换机行为分析)
  • docs/design/g5-simulator-design/02-multicore-interconnect.md (现有多核互连设计)

背景与动机

当前 G5 仿真器的范围

G5 仿真器目前覆盖 单芯片多核 场景:

SingleChipSim
├── CoreSubsys[0..N-1] (TIU + DMA + SDMA + HAU)
├── BusModel (2D mesh NoC, Manhattan 距离延迟)
└── SimKernel (全局事件队列)

02-multicore-interconnect.md 中设计了 C2C Link 和 CDMA Engine, 但采用的是简化的 alpha-beta 模型, 不反映 PAXI/RC Link 的实际硬件行为。

为什么需要 PAXI + Switch 建模

LLM 推理的并行策略 (TP/PP/DP/EP) 要求多芯片协作:

并行策略通信模式对互联的要求
TP (张量并行)AllReduce高带宽、低延迟, 芯片间频繁同步
PP (流水线并行)P2P Send/Recv中等带宽, 流水线阶段间传递
EP (专家并行)AllToAll高带宽, MoE 路由分发
DP (数据并行)AllReduce (梯度)大数据量, 可容忍较高延迟

PAXI + RC Link 是 SG2262 芯片间通信的实际协议栈, L2 Switch 是多芯片组网的核心设备。 要准确建模芯片间通信延迟, 必须替换简化的 alpha-beta 模型。

目标

  1. 实现 PAXILink 模型, 准确反映报文分片、协议开销、有效带宽、流控约束
  2. 实现 SwitchModel, 建模多跳网络中交换机引入的额外延迟
  3. 实现 CDMA 引擎, 作为 CoreSubsys 的第 5 个引擎驱动芯片间数据搬运
  4. 实现 MultiChipSim, 组装多芯片仿真
  5. 保持分层设计: Tier 1 (解析式) 先落地, 预留 Tier 2 (事件驱动) 扩展接口

系统架构

芯片间通信全路径

一次跨芯片数据传输经历以下阶段:

Chip A (发送端)                                          Chip B (接收端)
+----------+ +------+ +--------+ +------+ +------+ +--------+ +------+ +----------+
|CoreSubsys|-->| CDMA |-->| PAXI |-->| CESOC|--link--|Switch|--link--| CESOC|-->| PAXI |-->| CDMA |-->|CoreSubsys|
| (SDMA) | |Engine| |+RCLink | | MAC | | | | MAC | |+RCLink | |Engine| | (SDMA) |
+----------+ +------+ +--------+ +------+ +------+ +------+ +--------+ +------+ +----------+
^ ^
| PAXI Link Model Switch Model PAXI Link Model |
|<----- 片内 (Bus NoC) ---->|<-------------- 片间 (PAXI + Switch + PAXI) --------------------->|<-- 片内 -->|

模块层级

MultiChipSim (新增)
├── SingleChipSim[0] # 芯片 0: N 核 + BusModel + CDMA
├── SingleChipSim[1] # 芯片 1
├── ...
├── PAXILink[0→1] # 芯片 0 到芯片 1 的链路
├── PAXILink[1→0] # 反向链路
├── ...
├── SwitchModel[0] # 交换机 (多跳拓扑时使用)
├── SwitchModel[1] # ...
├── InterconnectTopology # 拓扑路由表 (src,dst) -> [link, switch, link, ...]
└── SimKernel # 全局事件队列 (所有芯片共享)

文件组织

backend/perf_model/L4_evaluation/g5/
├── kernel/ # 已有
├── chip/
│ ├── core_subsys.py # 已有, 需要新增 CDMA 引擎
│ └── bus.py # 已有
├── tiu.py, dma.py, sdma.py, hau.py # 已有
├── cdma.py # 新增: CDMA 引擎延迟计算
├── paxi_link.py # 新增: PAXI + RC Link + CESOC 链路模型
├── switch.py # 新增: L2 交换机模型
├── interconnect.py # 重写: 替换空 stub, 实现 InterconnectTopology
└── top/
├── single_chip.py # 已有
└── multi_chip.py # 新增: 多芯片组装

建模范围

PAXILink 将 PAXI (事务层) + RC Link (传输层) + CESOC (MAC/PHY) 建模为一条 点对点有向链路, 连接两个芯片。每条链路有独立的 TX 和 RX 方向。

建模要素:

  • 报文分片: 大块数据拆分为最大 1344B payload 的报文
  • 协议开销: 报头 + FCS + ICRC + FEC, 降低有效带宽
  • 流控约束: CBFC credit 限制在途数据量, 影响长距离吞吐
  • VC 隔离: 8 个虚拟通道, 不同流量类型独立流控

不建模的内容 (Tier 1):

  • Go-Back-N 重传 (假设无损网络)
  • Per-QP 速率控制 (假设无拥塞)
  • ACK/CNP MERGE 细节

报文格式与协议开销

来自 PAXI 分析文档, 各格式的报头开销:

格式报头 (无 VLAN)报头 (有 VLAN)有 ICRC有 FCS总开销
Standard50B54B4B4B58B / 62B
AFH_GEN122B26B4B4B30B / 34B
AFH_GEN2_16b22B26B4B4B30B / 34B
AFH_Lite12BN/A0B4B16B

有效带宽比 (payload / frame_size):

格式max payload=1344B 时有效比说明
Standard+VLAN1344 / 1406 = 95.6%最保守, 支持 ECN
AFH_GEN11344 / 1378 = 97.5%平衡方案
AFH_Lite1344 / 1360 = 98.8%最高效, 无重传保护

延迟模型

Tier 1: 解析式延迟

@dataclass
class PAXILinkConfig:
"""PAXI 链路配置

Attributes:
link_bandwidth_gbps: MAC 链路带宽
pkt_format: 报文格式 (standard/afh_gen1/afh_gen2_16b/afh_lite)
vlan_enabled: 是否启用 VLAN 标签
icrc_enabled: 是否启用 ICRC (仅 TYPE1)
fec_overhead_ratio: FEC 编码开销比例
axi_to_axi_base_latency_ns: AXI-to-AXI 最低延迟 (含 PAXI 流水线 + CESOC)
flow_control_mode: 流控模式 (cbfc/pfc)
vc_count: 虚拟通道数量
credit_limit_per_vc: 每 VC 最大 Credit 数
credit_size_bytes: 单个 Credit 代表的字节数
"""
link_bandwidth_gbps: float # 200 / 400
pkt_format: str # standard / afh_gen1 / afh_gen2_16b / afh_lite
vlan_enabled: bool # True / False
icrc_enabled: bool # True / False (afh_lite 始终 False)
fec_overhead_ratio: float # 典型 0.03 (3%)
axi_to_axi_base_latency_ns: float # 150 (400G C2C 直连)
flow_control_mode: str # cbfc / pfc
vc_count: int # 8
credit_limit_per_vc: int # per-VC 最大 credit
credit_size_bytes: int # 32 / 64 / 128 / 256 / 1024 / 2048

延迟计算:

def calc_paxi_latency(data_bytes: int, config: PAXILinkConfig) -> PAXIResult:
"""计算 PAXI 链路传输延迟

分三部分:
1. 首包延迟 (AXI-to-AXI 流水线)
2. 串行化延迟 (数据量 / 有效带宽)
3. 流控停顿 (credit RTT 导致的流水线气泡)
"""
max_payload = 1344 # TYPE1_PKT_LEN

# --- 报头开销 ---
header_bytes = _get_header_overhead(config.pkt_format, config.vlan_enabled)
icrc_bytes = 4 if config.icrc_enabled else 0
fcs_bytes = 4
frame_overhead = header_bytes + icrc_bytes + fcs_bytes

# --- 报文分片 ---
num_packets = math.ceil(data_bytes / max_payload)
# 最后一包可能不满
last_payload = data_bytes - (num_packets - 1) * max_payload
total_wire_bytes = (
(num_packets - 1) * (max_payload + frame_overhead)
+ (last_payload + frame_overhead)
)
# FEC 开销
total_wire_bytes_with_fec = total_wire_bytes / (1 - config.fec_overhead_ratio)

# --- 有效带宽 ---
# link_bandwidth_gbps 单位是 GB/s = bytes/ns
effective_bw_bytes_per_ns = config.link_bandwidth_gbps

# --- 延迟计算 ---
# 1) 首包延迟: PAXI TX 流水线 + CESOC + 链路传播 + CESOC RX + PAXI RX
first_packet_latency_ns = config.axi_to_axi_base_latency_ns

# 2) 串行化延迟: 数据灌入链路的时间
serialization_ns = total_wire_bytes_with_fec / effective_bw_bytes_per_ns

# 3) 流控停顿 (Tier 1 简化): credit 限制在途数据量
# CBFC 模式下, 每个 VC 最多 credit_limit * credit_size 字节在途
# 如果总数据量超过在途容量, 需要等待 credit 返还
max_inflight_per_vc = config.credit_limit_per_vc * config.credit_size_bytes
# 假设使用 1 个 VC 发送 (TYPE1_REQ 的 1 个 Bank)
max_inflight = max_inflight_per_vc
credit_stall_ns = 0.0
if data_bytes > max_inflight:
# credit RTT = 2 * (首包延迟 + 交换机延迟)
# 交换机延迟在外层叠加, 这里只算链路 RTT
credit_rtt_ns = 2 * first_packet_latency_ns
num_rounds = math.ceil(data_bytes / max_inflight)
credit_stall_ns = (num_rounds - 1) * credit_rtt_ns

total_latency_ns = first_packet_latency_ns + serialization_ns + credit_stall_ns

# --- 统计量 ---
payload_efficiency = data_bytes / total_wire_bytes_with_fec

return PAXIResult(
latency_ns=total_latency_ns,
data_bytes=data_bytes,
num_packets=num_packets,
total_wire_bytes=total_wire_bytes_with_fec,
first_packet_ns=first_packet_latency_ns,
serialization_ns=serialization_ns,
credit_stall_ns=credit_stall_ns,
payload_efficiency=payload_efficiency,
)


def _get_header_overhead(pkt_format: str, vlan_enabled: bool) -> int:
"""获取报头开销 (bytes), 不含 ICRC 和 FCS"""
table = {
# (format, vlan) -> header_bytes
("standard", False): 50, # MAC(12) + Eth_type(2) + IP(20) + UDP(8) + RH(8)
("standard", True): 54, # + VLAN(4)
("afh_gen1", False): 22, # AFH1(12) + Eth_type(2) + RH(8)
("afh_gen1", True): 26, # + VLAN(4)
("afh_gen2_16b", False): 22,
("afh_gen2_16b", True): 26,
("afh_lite", False): 12, # AFH2(12) only, 无 Eth_type/RH
("afh_lite", True): 12, # AFH_Lite 不支持 VLAN
}
key = (pkt_format, vlan_enabled)
if key not in table:
raise ValueError(f"Unknown PAXI format: {pkt_format}, vlan={vlan_enabled}")
return table[key]

Tier 2: 事件驱动扩展 (未来)

Tier 2 将 PAXILink 实现为 SimObject, 引入:

  • TX Pipeline: PAXI Flit Buffer → RC Link 序列化 → CESOC 发送
  • RX Pipeline: CESOC 接收 → RC Link 解析 → PAXI 解包
  • Credit 状态机: 每个 VC 独立跟踪 credit 余量
    • 发送前检查: credit[vc] >= packets_to_send
    • 发送后扣减: credit[vc] -= packets_sent
    • 收到返还时恢复: credit[vc] += credit_return
  • VC 仲裁: 多 VC 竞争 MAC 带宽时的调度
class PAXILinkSim(SimObject):
"""事件驱动 PAXI 链路 (Tier 2)

内部状态:
- credit_count[vc]: int (每 VC 当前可用 credit)
- tx_queue[vc]: deque (每 VC 发送队列)
- link_busy: bool (MAC 是否正在序列化)

事件流:
1. CDMA 提交请求 -> enqueue(vc, packet)
2. 仲裁器选择 VC -> dequeue + 检查 credit
3. credit 足够: 开始序列化, schedule(serialization_ns, on_tx_complete)
4. credit 不足: 阻塞, 等待 credit_return 事件唤醒
5. 对端收到: schedule(rx_pipeline_ns, deliver_to_cdma)
6. 对端返还 credit: schedule(credit_rtt, on_credit_return)
"""

报文格式选择指南

场景推荐格式理由
C2C 直连 (板内)AFH_Lite最小开销, 依赖 FEC 保证可靠性
交换机组网 + ECNStandard支持 IP/ECN, 交换机可标记拥塞
交换机组网 + PFCAFH_GEN1不需要 ECN, 用 PFC 逐跳流控
大规模组网 (64+ 芯片)Standard + VLAN需要 QoS 分类 + ECN + PFC 全功能

L2 Switch 模型

建模范围

SwitchModel 建模以太网 L2 交换机对 PAXI 报文的处理, 用于多跳网络场景。

建模要素:

  • 固定流水线延迟: 入口解析 + MAC 查表 + Crossbar 穿越 + 出口处理
  • 串行化延迟: 帧大小 / 端口带宽
  • 排队延迟: 多流竞争出口端口时的排队等待
  • PFC 交互: 出口队列满时向上游发送 PAUSE (Tier 2)

不建模的内容 (Tier 1):

  • ECN 标记 (端点行为)
  • DT 动态阈值缓冲管理细节
  • iSLIP 迭代过程

配置参数

@dataclass
class SwitchConfig:
"""L2 交换机配置

Attributes:
port_count: 端口数量
port_bandwidth_gbps: 端口带宽
forwarding_mode: 转发模式 (cut_through / store_and_forward)
fixed_latency_ns: 固定处理延迟 (入口 + 查表 + crossbar)
buffer_size_mb: 总缓冲大小
num_priorities: QoS 优先级数量
pfc_enabled: 是否启用 PFC
pfc_threshold_ratio: PFC 触发阈值 (队列深度占比)
"""
port_count: int # 8 / 16 / 32 / 64
port_bandwidth_gbps: float # 100 / 200 / 400
forwarding_mode: str # cut_through / store_and_forward
fixed_latency_ns: float # 300 ~ 800
buffer_size_mb: float # 16 / 32 / 64
num_priorities: int # 4 / 8
pfc_enabled: bool # True / False
pfc_threshold_ratio: float # 0.85 (85%)

延迟模型

Tier 1: 解析式延迟

def calc_switch_latency(
frame_size_bytes: int,
config: SwitchConfig,
egress_utilization: float = 0.0,
) -> SwitchResult:
"""计算单跳交换机延迟

Args:
frame_size_bytes: 以太网帧大小 (含报头 + payload + FCS)
config: 交换机配置
egress_utilization: 出口端口利用率 (0~1), 影响排队延迟

Returns:
SwitchResult 包含延迟分解
"""
bw_bytes_per_ns = config.port_bandwidth_gbps # GB/s = bytes/ns

# --- 1. 固定流水线延迟 ---
# 入口解析 + QoS 分类 + MAC 查表 + Crossbar 穿越
t_fixed = config.fixed_latency_ns

# --- 2. 串行化延迟 ---
# Cut-Through: 固定 (仅需接收帧头即可开始转发, 约 64B)
# Store-and-Forward: 完整帧接收后才转发
if config.forwarding_mode == "cut_through":
# Cut-Through 串行化 = 帧头 (最少 64B) 的接收时间
# 加出口侧完整帧发送时间 (两端并行, 延迟 = max(入口接收, 出口发送) - 重叠)
# 简化: 固定 ~100ns 额外串行化 (帧大小远小于 Jumbo)
t_serialization = 64 / bw_bytes_per_ns
else:
# Store-and-Forward: 完整帧接收 + 完整帧发送
t_serialization = frame_size_bytes / bw_bytes_per_ns

# --- 3. 排队延迟估算 ---
# M/D/1 排队论近似:
# W = (1/mu) * rho / (2 * (1 - rho))
# mu = bw / frame_size (帧/ns)
# rho = egress_utilization
t_queueing = 0.0
rho = min(egress_utilization, 0.99) # 避免除零
if rho > 0.01:
service_time = frame_size_bytes / bw_bytes_per_ns
t_queueing = service_time * rho / (2 * (1 - rho))

total_ns = t_fixed + t_serialization + t_queueing

return SwitchResult(
latency_ns=total_ns,
fixed_ns=t_fixed,
serialization_ns=t_serialization,
queueing_ns=t_queueing,
)

典型延迟值 (PAXI 最大帧 ~1406B):

场景固定串行化 (CT)排队 (rho=0)总计
200GbE, idle500ns0.32ns0~500ns
200GbE, 50% load500ns0.32ns3.5ns~504ns
200GbE, 80% load500ns0.32ns14ns~514ns
400GbE, idle300ns0.16ns0~300ns
400GbE, 80% load300ns0.16ns7ns~307ns

多跳延迟

def calc_multihop_switch_latency(
frame_size_bytes: int,
switch_configs: list[SwitchConfig],
link_propagation_ns_per_hop: float = 5.0,
egress_utilizations: list[float] | None = None,
) -> float:
"""计算多跳交换机网络延迟

Args:
frame_size_bytes: 帧大小
switch_configs: 每跳交换机配置 (支持异构)
link_propagation_ns_per_hop: 跳间链路传播延迟
egress_utilizations: 每跳出口利用率

Returns:
总延迟 (ns)
"""
total = 0.0
for i, sw_cfg in enumerate(switch_configs):
rho = egress_utilizations[i] if egress_utilizations else 0.0
result = calc_switch_latency(frame_size_bytes, sw_cfg, rho)
total += result.latency_ns + link_propagation_ns_per_hop
return total

Tier 2: 事件驱动扩展 (未来)

class SwitchSim(SimObject):
"""事件驱动 L2 交换机 (Tier 2)

内部状态:
- voq[in_port][out_port][priority]: deque # VOQ 队列
- egress_queue[out_port][priority]: deque # 出口队列
- buffer_used: int # 已用缓冲 (bytes)
- pfc_paused[out_port][priority]: bool # PFC 暂停状态

事件流:
1. 帧到达入口 -> 解析 (fixed_latency) -> VOQ 入队
2. iSLIP 调度: 每个 time_slot 选择 VOQ -> crossbar 传输
3. 出口调度: SP (ACK/CNP) + WRR (REQ/RSP)
4. 帧出口: 串行化延迟后离开交换机
5. PFC: 出口队列深度超阈值时, 向入口端口发 PAUSE 事件
"""

交换机与 PAXI 报文格式的交互

来自 Switch 分析文档的关键约束:

PAXI 格式ECN 支持PFC 支持QoS 来源建模影响
Standard有 (IP头)有 (VLAN PCP)DSCP / VLAN PCP交换机可标记 ECN, 按 PCP 分队列
AFH_GEN1有 (VLAN PCP)VLAN PCP / TC域无 ECN, 仅 PFC 控拥塞
AFH_Lite仅端口默认端口默认优先级所有帧入同一队列, 无 QoS 区分

Tier 1 中不区分格式对交换机行为的影响 (假设理想调度)。 Tier 2 中需要根据格式决定 QoS 映射和 PFC 优先级。


CDMA 引擎

定位

CDMA (Cross-chip DMA) 是 CoreSubsys 的第 5 个引擎, 负责驱动芯片间数据搬运。 发出的请求通过 PAXILink (+SwitchModel) 到达远端芯片。

对标 TPUPerf: c_model/src/sg2260/cdma.cc (1191 行)。

命令类型

class CDMAOpType(Enum):
SEND = "send" # 向远端发送数据
RECV = "recv" # 等待远端数据到达
ALL_REDUCE = "all_reduce" # 集合通信 (简化)
ALL_TO_ALL = "all_to_all" # MoE 路由 (简化)
ALL_GATHER = "all_gather" # PP/SP 数据聚合


@dataclass
class CDMACommand:
"""CDMA 指令

Attributes:
cmd_id: 指令 ID
cmd_id_dep: 依赖的指令 ID
dep_engine: 依赖的引擎名
op_type: 操作类型
data_bytes: 数据量
remote_chip_id: 远端芯片 ID (SEND/RECV 时使用)
chip_group: 参与的芯片组 (集合通信时使用)
source_op_id: 来源操作 ID (关联 L3 层)
"""
cmd_id: int
cmd_id_dep: int
dep_engine: str
op_type: CDMAOpType
data_bytes: int
remote_chip_id: int = -1
chip_group: list[int] = field(default_factory=list)
source_op_id: str = ""

延迟计算

SEND / RECV

SEND 和 RECV 是配对操作: 一端 SEND, 另一端 RECV。

从 CDMA 发起到数据到达远端, 延迟分解为:

T_send = T_bus_local + T_paxi_link + T_switch_hops + T_bus_remote

其中:
- T_bus_local: 本地 CDMA → Bus → LMEM/DDR 读取 (复用 BusModel)
- T_paxi_link: PAXI 链路传输 (调用 calc_paxi_latency)
- T_switch_hops: 交换机跳数延迟 (调用 calc_switch_latency × N)
- T_bus_remote: 远端写入 (复用 BusModel)

RECV 的延迟 = 等待对端 SEND 完成 (通过 SimKernel 事件同步)。

实现为信用流控:

RECV 端:
1. 分配接收缓冲
2. 发送 credit 到对端 (通过 PAXI 反向链路)
3. 等待数据到达

SEND 端:
1. 等待 credit (credit_fifo)
2. 读取本地数据
3. 通过 PAXI 链路发送到远端
4. 完成

集合通信

对标 TPUPerf 的 FAKE_ALL_REDUCE:

def calc_cdma_collective_latency(
op_type: CDMAOpType,
data_bytes: int,
chip_count: int,
paxi_config: PAXILinkConfig,
switch_configs: list[SwitchConfig],
algorithm: str = "ring",
) -> CDMAResult:
"""计算集合通信延迟

使用 alpha-beta 模型, 但 alpha 和 beta 从 PAXI + Switch 模型推导。
"""
# 从 PAXI Link 推导单次传输参数
# alpha = 首包延迟 (PAXI pipeline + Switch 固定延迟)
# beta = 每字节传输时间 (1 / effective_bandwidth)

# 单跳 PAXI 延迟 (0 字节, 只算固定延迟)
alpha_result = calc_paxi_latency(0, paxi_config)
alpha_ns = alpha_result.first_packet_ns
# 加交换机固定延迟
for sw in switch_configs:
alpha_ns += sw.fixed_latency_ns

# 有效带宽 (考虑报头开销和 FEC)
efficiency = _calc_payload_efficiency(paxi_config)
effective_bw = paxi_config.link_bandwidth_gbps * efficiency
beta_ns_per_byte = 1.0 / effective_bw # ns/byte

n = chip_count

if op_type == CDMAOpType.ALL_REDUCE:
if algorithm == "ring":
# Ring AllReduce: 2*(n-1) steps, 每步传 data_bytes/n
steps = 2 * (n - 1)
chunk_bytes = data_bytes / n
latency = steps * alpha_ns + steps * chunk_bytes * beta_ns_per_byte
elif algorithm == "tree":
# Tree AllReduce: 2*log2(n) steps, 每步传 data_bytes
steps = 2 * math.ceil(math.log2(n))
latency = steps * alpha_ns + 2 * data_bytes * beta_ns_per_byte

elif op_type == CDMAOpType.ALL_TO_ALL:
if algorithm == "pairwise":
# Pairwise AllToAll: (n-1) steps, 每步传 data_bytes/n
steps = n - 1
chunk_bytes = data_bytes / n
latency = steps * (alpha_ns + chunk_bytes * beta_ns_per_byte)
elif algorithm == "ring":
steps = n - 1
chunk_bytes = data_bytes / n
latency = steps * alpha_ns + steps * chunk_bytes * beta_ns_per_byte

elif op_type == CDMAOpType.ALL_GATHER:
if algorithm == "ring":
# Ring AllGather: (n-1) steps, 每步传 data_bytes/n
steps = n - 1
chunk_bytes = data_bytes / n
latency = steps * alpha_ns + steps * chunk_bytes * beta_ns_per_byte

# credit stall (大数据量时)
max_inflight = paxi_config.credit_limit_per_vc * paxi_config.credit_size_bytes
total_transferred = _total_bytes_transferred(op_type, algorithm, data_bytes, n)
if total_transferred > max_inflight:
credit_rtt = 2 * alpha_ns
num_stalls = math.ceil(total_transferred / max_inflight) - 1
latency += num_stalls * credit_rtt

return CDMAResult(
latency_ns=latency,
data_bytes=data_bytes,
op_type=op_type,
algorithm=algorithm,
alpha_ns=alpha_ns,
beta_ns_per_byte=beta_ns_per_byte,
)

CoreSubsys 集成

chip/core_subsys.py 中新增第 5 个引擎:

class CoreSubsys(SimObject):
def __init__(self, ..., c2c_delay_fn=None):
# ... 现有 4 引擎 ...

# CDMA 引擎 (跨芯片 DMA)
self._cdma_busy: bool = False
self._cdma_idx: int = 0
self._cdma_sync_id: int = 0
self._cdma_cmds: list = []
self._c2c_delay_fn = c2c_delay_fn # (remote_chip, data_bytes) -> delay_ns

# CDMA 统计
self._cdma_stats = StatGroup("cdma", parent=self.stats)
self._stat_cdma_cmd = self._cdma_stats.scalar("cmd_count", "CDMA 指令数")
self._stat_cdma_bytes = self._cdma_stats.scalar("total_bytes", "总传输字节数")
self._stat_cdma_by_op = self._cdma_stats.vector("cmd_by_op", "按操作分的指令数")

def _try_issue_cdma(self):
if self._cdma_busy or self._cdma_idx >= len(self._cdma_cmds):
return
cmd = self._cdma_cmds[self._cdma_idx]
dep_val = self.get_sync_id(cmd.dep_engine)
if cmd.cmd_id_dep <= dep_val:
self._cdma_idx += 1
self._cdma_busy = True
# 延迟 = CDMA 本身 + PAXI Link + Switch
latency_ns = self._c2c_delay_fn(cmd.remote_chip_id, cmd.data_bytes)
start = self.now()
end = start + latency_ns
self._records.append(SimRecord(
engine="CDMA", cmd_id=cmd.cmd_id,
start_ns=start, end_ns=end,
data_bytes=cmd.data_bytes,
source_op_id=cmd.source_op_id,
))
# 统计
self._stat_cdma_cmd.inc()
self._stat_cdma_bytes.inc(cmd.data_bytes)
self._stat_cdma_by_op.inc(cmd.op_type.name)
self._stat_total_instr.inc()
self._stat_cmd_by_engine.inc("CDMA")
cid = cmd.cmd_id
self.schedule_at(end, lambda: self._on_cdma_finish(cid))

def _on_cdma_finish(self, cmd_id):
self._cdma_sync_id = cmd_id
self._cdma_busy = False
self._try_issue_all()

def get_sync_id(self, engine: str) -> int:
# ... 现有 ...
if engine == "cdma":
return self._cdma_sync_id
return 0

def _try_issue_all(self):
self._try_issue_dma()
self._try_issue_tiu()
self._try_issue_sdma()
self._try_issue_hau()
self._try_issue_cdma() # 新增

InterconnectTopology (多芯片拓扑)

职责

替换当前空的 interconnect.py, 管理多芯片间的连接关系和路由。

@dataclass
class ChipLink:
"""两芯片间的链路描述"""
src_chip: int
dst_chip: int
paxi_config: PAXILinkConfig
switch_hops: list[SwitchConfig] # 中间经过的交换机 (0=直连)
link_propagation_ns: float # 物理链路传播延迟


class InterconnectTopology:
"""多芯片互联拓扑

管理:
- 芯片间链路注册
- 路由表: (src, dst) -> ChipLink
- 延迟查询: get_c2c_delay(src, dst, data_bytes)
"""

def __init__(self):
self._links: dict[tuple[int, int], ChipLink] = {}

def add_link(self, link: ChipLink):
self._links[(link.src_chip, link.dst_chip)] = link

def get_c2c_delay(self, src_chip: int, dst_chip: int, data_bytes: int) -> float:
"""查询芯片间传输延迟

1. 查路由表获取链路和中间交换机
2. calc_paxi_latency() 算链路延迟
3. calc_switch_latency() × N 算交换机延迟
4. 返回总延迟
"""
link = self._links.get((src_chip, dst_chip))
if link is None:
raise ValueError(
f"No link from chip {src_chip} to chip {dst_chip}"
)

# PAXI 链路延迟
paxi_result = calc_paxi_latency(data_bytes, link.paxi_config)

# 交换机延迟
switch_total = 0.0
for sw_config in link.switch_hops:
sw_result = calc_switch_latency(
frame_size_bytes=_estimate_frame_size(data_bytes, link.paxi_config),
config=sw_config,
)
switch_total += sw_result.latency_ns

# 链路传播延迟
prop_total = link.link_propagation_ns * (len(link.switch_hops) + 1)

return paxi_result.latency_ns + switch_total + prop_total

拓扑构建

从现有的 topology YAML 配置构建:

def build_topology_from_config(
topology_config: dict,
hardware_params: dict,
) -> InterconnectTopology:
"""从配置文件构建多芯片拓扑

topology_config 格式示例:
interconnect:
c2c:
bandwidth_gbps: 448
latency_us: 0.2
b2b:
bandwidth_gbps: 400
latency_us: 2.0
switch_hops: 1
switch_config:
fixed_latency_ns: 500
forwarding_mode: cut_through
"""
topo = InterconnectTopology()
# 根据芯片位置关系确定链路类型 (c2c/b2b/r2r/p2p)
# 为每对芯片创建 ChipLink
# ...
return topo

MultiChipSim (多芯片组装)

组装流程

class MultiChipSim:
"""多芯片仿真器

组装:
1. 创建 SimKernel (所有芯片共享)
2. 创建 InterconnectTopology
3. 为每个芯片创建 SingleChipSim (共享 kernel)
4. 为每个芯片的 CDMA 引擎绑定 c2c_delay_fn
5. 加载各芯片的指令
6. kernel.run()
7. 收集所有芯片的 SimRecord + 统计
"""

def __init__(
self,
chips: list[ChipSpecImpl],
topology: InterconnectTopology,
):
self._chips = chips
self._topology = topology

def simulate(
self,
programs: dict[int, CoreProgram], # chip_id -> CoreProgram
) -> list[SimRecord]:
kernel = SimKernel()

# 为每个芯片创建核心
chip_sims = {}
for chip_id, chip in enumerate(self._chips):
kernel.add_clock(f"chip{chip_id}_tpu", chip.get_tiu_frequency())
# c2c_delay_fn 捕获拓扑信息
def make_c2c_fn(src_id):
def fn(dst_chip, data_bytes):
return self._topology.get_c2c_delay(src_id, dst_chip, data_bytes)
return fn

sim = SingleChipSim(chip, kernel=kernel, c2c_delay_fn=make_c2c_fn(chip_id))
chip_sims[chip_id] = sim

# 加载指令
for chip_id, program in programs.items():
chip_sims[chip_id].load_program(program)

# 运行
kernel.run()

# 收集结果
all_records = []
for sim in chip_sims.values():
all_records.extend(sim.get_records())
all_records.sort(key=lambda r: (r.start_ns, r.cmd_id))
return all_records

SingleChipSim 修改

需要修改 top/single_chip.py 以支持:

  1. 接受外部注入的 SimKernel (多芯片共享)
  2. 接受 c2c_delay_fn 传递给 CoreSubsys
  3. 分离 load_program()run() (由 MultiChipSim 统一调度)

端到端延迟示例

场景 A: 8 芯片板内直连 (C2C, 无交换机)

配置:
- 链路: 400G PAXI (AFH_Lite), C2C 直连
- axi_to_axi_latency: 150ns
- credit_limit: 512, credit_size: 256B (128KB 在途)

TP AllReduce 128KB (8 芯片, Ring):
alpha = 150ns
efficiency = 1344/1360 * (1-0.03) = 95.8%
effective_bw = 400 * 0.958 = 383.2 GB/s
beta = 1/383.2 = 0.00261 ns/byte

Ring: 2*(8-1) steps, chunk = 128KB/8 = 16KB
T = 14 * 150ns + 14 * 16384 * 0.00261
= 2100ns + 599ns
= 2699ns (2.7us)

场景 B: 32 芯片交换机组网 (1 跳 Switch)

配置:
- 链路: 200G PAXI (Standard+VLAN)
- 交换机: 32 端口 200GbE, Cut-Through, 固定延迟 500ns
- axi_to_axi_latency: 200ns (含交换机传播)
- credit_limit: 256, credit_size: 256B (64KB 在途)

TP AllReduce 1MB (32 芯片, Ring):
alpha = 200ns + 500ns (switch) = 700ns
efficiency = 1344/1406 * (1-0.03) = 92.7%
effective_bw = 200 * 0.927 = 185.4 GB/s
beta = 1/185.4 = 0.00539 ns/byte

Ring: 2*(32-1) = 62 steps, chunk = 1MB/32 = 32KB
T = 62 * 700ns + 62 * 32768 * 0.00539
= 43400ns + 10948ns
= 54348ns (54.3us)

credit stall:
max_inflight = 64KB, total per step = 32KB -> 不触发
(如果 chunk > 64KB, 会有额外停顿)

场景 C: 64+ 芯片 Fat-Tree (2 跳 Switch)

配置:
- 链路: 200G PAXI (Standard+VLAN)
- 交换机: ToR 16端口 + Spine 32端口, 各 500ns 固定延迟
- 跳间传播: 5ns/hop
- axi_to_axi_latency: 200ns

EP AllToAll 2MB (64 芯片, Pairwise):
alpha = 200ns + 2*500ns + 2*5ns = 1210ns
beta = 0.00539 ns/byte (同上)

Pairwise: 63 steps, chunk = 2MB/64 = 32KB
T = 63 * (1210 + 32768 * 0.00539)
= 63 * (1210 + 176.6)
= 63 * 1386.6
= 87356ns (87.4us)

配置加载与 YAML 扩展

芯片配置扩展

在现有 chip_presets/*.yaml 中新增 PAXI 相关配置:

# chip_presets/sg2262.yaml 扩展
paxi:
pkt_format: "afh_lite" # 默认报文格式
vlan_enabled: false
icrc_enabled: false
fec_overhead_ratio: 0.03
flow_control_mode: "cbfc"
vc_count: 8
credit_limit_per_vc: 512
credit_size_bytes: 256

拓扑配置扩展

在现有 topologies/*.yaml 中新增交换机配置:

# topologies/P1-R1-B4-C32.yaml 扩展
hardware_params:
interconnect:
c2c:
bandwidth_gbps: 448
latency_us: 0.2
# 新增: PAXI 参数覆盖 (板内直连可用精简格式)
paxi_override:
pkt_format: "afh_lite"
axi_to_axi_base_latency_ns: 150
b2b:
bandwidth_gbps: 200
latency_us: 2.0
# 新增: 交换机配置
switch:
port_count: 16
forwarding_mode: "cut_through"
fixed_latency_ns: 500
buffer_size_mb: 32
num_priorities: 4
pfc_enabled: true
pfc_threshold_ratio: 0.85
# 新增: PAXI 参数覆盖 (经交换机使用 Standard 格式)
paxi_override:
pkt_format: "standard"
vlan_enabled: true
axi_to_axi_base_latency_ns: 200

实现计划

任务工作量说明
PAXILinkConfig + PAXIResult 数据类0.5 天配置和结果定义
calc_paxi_latency()1 天Tier 1 延迟公式
CDMACommand 数据类0.5 天指令定义 (L3 层)
calc_cdma_latency() (SEND/RECV)1 天点对点延迟
calc_cdma_collective_latency()2 天Ring/Tree AllReduce, Pairwise AllToAll
CoreSubsys CDMA 集成1 天第 5 引擎 + 同步 + 统计
单元测试1 天延迟公式验证
配置加载1 天YAML 解析 PAXI 参数

Phase 2: Switch 模型 + 多芯片组装 [2-3 周]

任务工作量说明
SwitchConfig + SwitchResult 数据类0.5 天
calc_switch_latency()1 天Tier 1 含 M/D/1 排队
InterconnectTopology2 天路由表 + 延迟查询
build_topology_from_config()1 天YAML → Topology
MultiChipSim2 天多芯片组装 + 共享 kernel
SingleChipSim 改造1 天支持外部 kernel + c2c_delay_fn
集成测试2 天多芯片 AllReduce 场景

Phase 3: Tier 2 事件驱动 (未来) [4-6 周]

任务工作量说明
PAXILinkSim (SimObject)3 天Credit 状态机 + VC 仲裁
SwitchSim (SimObject)5 天VOQ + iSLIP + DT buffer
PFC 逐跳传播3 天PAUSE 帧事件链
拥塞场景验证3 天Incast / 多流竞争
统计扩展1 天Switch 队列深度、PFC 事件计数

与现有设计的关系

替换 02-multicore-interconnect.md 中的 C2C/CDMA

02 文档中的 C2C 模型 (link_bw=11.2 GB/s, alpha=0.25us, beta=0.3us) 和 CDMA 模型 (SEND/RECV/FAKE_ALL_REDUCE) 作为早期简化设计保留参考, 但实现时由本文档的 PAXILink + CDMA 模型替代。

关键差异:

维度02 文档 (简化)本文档 (PAXI)
带宽建模固定 link_bw考虑报头开销和 FEC 的有效带宽
延迟模型alpha-beta 经验值从硬件参数推导 (axi_to_axi + serialization + credit)
流控简化 credit (capacity=2)CBFC per-VC credit, 可配置粒度和深度
交换机不涉及完整交换机模型 (固定延迟 + 排队 + PFC)
报文格式不涉及4 种格式, 不同开销和功能支持
集合通信FAKE_ALL_REDUCE 一个公式Ring/Tree/Pairwise 分算法建模

L2_arch/interconnect.py 的关系

现有 L2_arch/interconnect.py 中的 ChipInterconnectSpecImplRingAllReduceModel / TreeAllReduceModel 是面向数学建模层 (非指令级) 的抽象。

G5 仿真器中的 PAXILink / SwitchModel 是面向指令级仿真的更细粒度模型。 两者可以共存:

  • 数学建模路径: L2_arch ChipInterconnectSpecImpl → 快速估算
  • 指令级仿真路径: L4_evaluation/g5 PAXILink + SwitchModel → 精确仿真