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 模型。
目标
- 实现 PAXILink 模型, 准确反映报文分片、协议开销、有效带宽、流控约束
- 实现 SwitchModel, 建模多跳网络中交换机引入的额外延迟
- 实现 CDMA 引擎, 作为 CoreSubsys 的第 5 个引擎驱动芯片间数据搬运
- 实现 MultiChipSim, 组装多芯片仿真
- 保持分层设计: 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 # 新增: 多芯片组装
PAXI Link 模型
建模范围
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 | 总开销 |
|---|---|---|---|---|---|
| Standard | 50B | 54B | 4B | 4B | 58B / 62B |
| AFH_GEN1 | 22B | 26B | 4B | 4B | 30B / 34B |
| AFH_GEN2_16b | 22B | 26B | 4B | 4B | 30B / 34B |
| AFH_Lite | 12B | N/A | 0B | 4B | 16B |
有效带宽比 (payload / frame_size):
| 格式 | max payload=1344B 时有效比 | 说明 |
|---|---|---|
| Standard+VLAN | 1344 / 1406 = 95.6% | 最保守, 支持 ECN |
| AFH_GEN1 | 1344 / 1378 = 97.5% | 平衡方案 |
| AFH_Lite | 1344 / 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 保证可靠性 |
| 交换机组网 + ECN | Standard | 支持 IP/ECN, 交换机可标记拥塞 |
| 交换机组网 + PFC | AFH_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, idle | 500ns | 0.32ns | 0 | ~500ns |
| 200GbE, 50% load | 500ns | 0.32ns | 3.5ns | ~504ns |
| 200GbE, 80% load | 500ns | 0.32ns | 14ns | ~514ns |
| 400GbE, idle | 300ns | 0.16ns | 0 | ~300ns |
| 400GbE, 80% load | 300ns | 0.16ns | 7ns | ~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 以支持:
- 接受外部注入的
SimKernel(多芯片共享) - 接受
c2c_delay_fn传递给 CoreSubsys - 分离
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
实现计划
Phase 1: PAXI Link 解析式模型 + CDMA 引擎 [2-3 周]
| 任务 | 工作量 | 说明 |
|---|---|---|
| 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 排队 |
| InterconnectTopology | 2 天 | 路由表 + 延迟查询 |
| build_topology_from_config() | 1 天 | YAML → Topology |
| MultiChipSim | 2 天 | 多芯片组装 + 共享 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 中的 ChipInterconnectSpecImpl 和
RingAllReduceModel / TreeAllReduceModel 是面向数学建模层 (非指令级) 的抽象。
G5 仿真器中的 PAXILink / SwitchModel 是面向指令级仿真的更细粒度模型。 两者可以共存:
- 数学建模路径: L2_arch
ChipInterconnectSpecImpl→ 快速估算 - 指令级仿真路径: L4_evaluation/g5
PAXILink + SwitchModel→ 精确仿真