第一部分:六大协议层面损耗来源
PCIe 数据从事务层生成,经数据链路层加固可靠传输信息,最终由物理层编码发送,三层叠加产生六类性能损耗:
1. 编解码开销
| Gen1 (2.5GT/s) / Gen2 (5GT/s) | 8b/10b | 20% |
| Gen3 (8GT/s) 及以上 | 128b/130b | ≈1.54%,基本可忽略 |
Gen3 相比 Gen2 单 lane 速率仅翻倍(5→8GT/s),但有效带宽提升近 2 倍,核心原因就是编码效率从 80% 跃升到 ~98.5%。
2. TLP 包开销
单个 TLP 除 Payload 外携带的固定开销:
- Header:3DW=12B(32位地址)或 4DW=16B(64位地址)
- ECRC:4B(可选,端到端校验)
- Sequence Number:2B(数据链路层加,用于排序和重传)
- LCRC:4B(数据链路层加的链路级CRC)
- Start/End 帧标记:物理层加帧标记
合计约 20~30B/TLP,固定开销不随 Payload 大小变化,所以 MPS 越大占比越小。
3. 传输开销(SKP Ordered Set)
收发两端各自使用独立参考时钟,存在 ppm 级频率偏差,需周期性插入 SKP Ordered Set 做时钟补偿:
- Gen1/2:4B
- Gen3 及以上:16B(因编码块结构变化)
限制:SKP 只能插在 TLP/DLLP 间隙,不能打断正在传输的包。
4. 链路协议开销(ACK/NAK)
每个 TLP 需被确认以支持重传机制,但可攒批:
- 攒几个 TLP 回一次 Ack DLLP,减少 DLLP 数量
- 代价:发送端 Retry Buffer 必须保留所有未确认 TLP,需要更大缓冲区,同时受 Ack 超时定时器约束
5. 流控开销(UpdateFC)
UpdateFC DLLP 告知对方缓存剩余容量(Posted/Non-Posted/Completion 三类,Header/Data 分开计):
- 发送频率越低,性能越好
- 代价:接收端需要更大的物理缓冲区兜底延迟感知
6. 系统参数
- MPS:单 TLP 最大 Payload
- Max Read Request Size (MRRS):单次读请求最大申请量
- RCB(Read Completion Boundary):64B/128B,决定读完成包拆分粒度
第二部分:带宽计算示例(Gen1 x8)
基础参数: SymbolTime=4ns,每 4ns 传 8B 有效数据
场景:MPS=128B,200 个 MemWr
TLP传输时间 = (128+20)/8 × 4ns = 74ns
DLLP传输时间 = 4ns
ACK:每5个TLP回1次 → 200/5=40个
FC :每4个TLP发1次 → 200/4=50个
总耗时 = 200×74ns + (40+50)×4ns = 14800+360 = 15160ns
总数据 = 200×128B = 25600B
带宽 = 25600/15160 ≈ 1689 MB/s
MPS 调至 512B(其余不变):
TLP传输时间 = (512+20)/8 × 4ns = 266ns
总耗时 = 200×266ns + 90×4ns = 53200+360 = 53560ns
总数据 = 200×512B = 102400B
带宽 = 102400/53560 ≈ 1912 MB/s
结论: MPS 从 128B→512B,带宽提升约 13%,本质是固定包头开销被更大 Payload 摊薄。
第三部分:链路调用流程详解
1. TLP 分层封装流程
【事务层】组装 Header+Payload+(ECRC)
↓
【数据链路层】加 Sequence Number(2B) + 计算LCRC(4B) → 存入Retry Buffer
↓
【物理层】加Start/End帧标记 → 8b/10b或128b/130b编码 → 与SKP/DLLP竞争时隙发送
Sequence Number 和 LCRC 由数据链路层加,对软件透明;写入 Retry Buffer 与发送同时发生,保证 NAK/超时后能立即重发。
2. 写事务(Posted)流程——MemWr
Requester Completer
1.检查Posted Credit是否够
2.发送MemWr TLP ────────────────────→
(存入Retry Buffer,启动ACK超时计时器)
3.校验LCRC/Seq,写入接收缓冲区
←──────────────────────── 4.Ack DLLP(可攒批)
5.释放Retry Buffer中已被Ack的TLP
- 第1步是流控闭环起点,Credit不够必须停发
- 第4步的攒批策略:Ack延迟定时器 + 门限计数器,谁先触发就发
- 若Ack超时未到,触发Replay:Retry Buffer中所有未确认TLP按序重发
3. 读事务(Non-Posted)流程——MemRd
Requester Completer
1.检查Non-Posted Credit(仅Header,无Data)
2.发送MemRd TLP(带Tag) ─────────────→
(Retry Buffer保存请求,等Ack)
3.取数据
4.按RCB边界拆分成若干CplD
←──────────────────────── 5.Ack(针对请求TLP)
←──────────────────────── 6.逐个发送CplD(带Tag对应)
7.检查Completion Credit是否够(反向流控)
8.收满所有CplD或超时→关闭事务
────────────────────────→ 9.Ack(针对CplD)
关键隐藏因素:
- 第4步拆分对应RCB参数,地址未对齐时可能拆出更多CplD,读方向额外损耗高于写方向
- 第7步反向流控常被忽略:Completion同样占用信用额度,Requester侧Completion缓冲区太小会限制Completer连续发送的CplD数
- Tag数量(8-bit可到256个,需Extended Tag使能)决定同时在途读请求数,Tag不够会导致提前节流——比MPS更隐蔽的性能瓶颈根因
4. 流控信用(FC Credit)生命周期
【链路Training完成 —— FC Initialization】
Completer清点Posted/Non-Posted/Cpl三类缓冲区初始容量
↓
发送InitFC1 → InitFC2
↓
Requester建立"对方初始信用余额"账本
【链路进入L0正常工作 —— Update阶段,持续循环】
Requester发TLP→本地账本扣减
Completer消费TLP→腾出空间
↓
Completer周期性/门限触发 UpdateFC DLLP
↓
Requester刷新账本,解除因Credit不足的阻塞
UpdateFC传递的是绝对余额值而非增量,丢一个包不严重(下一个会自动纠正),这一设计避免账本永久失步。
5. ACK/NAK 重传异常流程
Completer检测LCRC失败或Sequence不连续
↓
发送Nak DLLP(携带最后一个正确收到的SeqNum)
↓
Requester从Retry Buffer中,把该序号之后所有TLP全部重发(Go-Back-N)
↓
新产生的TLP需排队等待重传先完成
一次丢包代价 = 重发"从丢失点到当前所有已发未确认的TLP",Retry Buffer越大单次重传代价越高,但太小又因Ack不及时降低吞吐。
6. 物理层时隙争夺视图
[TLP1 74ns][TLP2 74ns][SKP 4ns][TLP3 74ns][ACK 4ns][TLP4 74ns][TLP5 74ns][FC 4ns]…
DLLP和SKP只能插在TLP间隙,串行抢占同一物理通道时间。SKP周期性要求通常优先保证,MPS调大本质是拉长TLP长度、相对减少空隙出现频次。
7. 调优优先级总结
第四部分:MPS(Max Payload Size)深度解析
1. 全称与易混淆概念
MPS = Max Payload Size(最大有效载荷大小)
| MPS | Max Payload Size | 单TLP的Payload最大字节数 |
| MRRS | Max Read Request Size | 单次读请求申请的最大数据量 |
两者独立配置但相互影响。
2. 取值范围
128B / 256B / 512B / 1024B / 2048B / 4096B
复制代码
实际常见配置为 128B 或 256B,很少配到 1024B 以上。
3. 协商机制(木桶效应)
每个设备在Device Capabilities中声明MPS支持能力
↓
系统软件遍历链路上所有设备
↓
取所有设备支持值的最小值
↓
写入每个设备Device Control寄存器,作为实际生效值
链路上任一短板设备都会拉低全链路MPS,诊断时对比:
DevCap: MaxPayload 512 bytes ← 物理支持能力
DevCtl: MaxPayload 128 bytes ← 实际协商生效值
两者不一致往往就是瓶颈所在。
4. 作用原理
固定开销不随Payload变化,MPS越大→固定开销占比越小→有效带宽越高(第二部分算例已验证:128B→512B提升约13%)。
5. 反面代价
- 占用更大发送/接收缓冲区(Retry Buffer容量线性增长)
- 单包时延变长,可能影响时延敏感的小包(如中断Message TLP需排队等待)
- 重传代价随Payload增大成比例放大
- 受限于链路最短板设备,实际可调空间有限
6. MPS 与 MRRS 联动
MemRd声明数据量 ≤ MRRS
↓
Completer返回时,每个CplD Payload ≤ MPS
↓
若MRRS > MPS,则必须拆成多个CplD才能返回完整数据
单独调大MRRS而不同步考虑MPS,收益有限甚至因拆包增多而适得其反。
7. 实际调优建议
- 先排查链路上所有设备DevCap,定位瓶颈设备
- 硬件允许时优先提到256B或512B(多数平台的甜蜜点)
- 批量吞吐场景优先调大MPS;时延敏感场景需谨慎评估大包排队影响
- 涉及BIOS/寄存器配置修改,生产环境建议先在测试环境验证




