2. PCIe基础回顾
要定位PCIe吞吐瓶颈,必须先回到协议本身。PCIe不是一条“透明的高速导线”,而是一套严格分层的串行互连协议。一次内存读请求从CPU发出,到数据返回,中间要穿过事务层、数据链路层和物理层,每一层都有自己的封装、流控、重传和时钟域处理。吞吐瓶颈可能出现在任意一层:事务层受限于Tag数量,数据链路层受限于ACK/NAK与重传,物理层受限于链路宽度、速率和编码效率。理解分层,就是理解“瓶颈可能藏在哪里”。
一、PCIe三层结构:各司其职的流水线
PCIe协议从高到低分为三层,发送方向逐层封装,接收方向逐层解封装:
- 事务层(Transaction Layer):负责生成和解析TLP(Transaction Layer Packet),管理请求、完成、配置、消息等事务,并维护基于Credit的流控机制。它决定“发什么、能不能发”。
- 数据链路层(Data Link Layer):负责TLP的可靠传输,添加序列号(Sequence Number)和LCRC,生成DLLP(Data Link Layer Packet),通过ACK/NAK实现重传。它决定“发得可不可靠”。
- 物理层(Physical Layer):负责字节条带化、加扰、编码(8b/10b或128b/130b)、串并转换、差分信号发送与接收,以及链路训练和状态机(LTSSM)。它决定“电气上能不能跑起来、跑多快”。
三层之间是服务关系:事务层把TLP交给数据链路层,数据链路层加上可靠传输信息后交给物理层;接收端则反向剥离。任何一层出现拥塞、错误或配置不当,都会直接反映为上层看到的吞吐下降或延迟抖动。
二、TLP与DLLP:两种包,两种职责
PCIe链路上传输的包分为两大类,理解它们的区别是分析吞吐问题的关键:
| 对比项 | TLP(事务层包) | DLLP(数据链路层包) |
|---|---|---|
| 生成层 | 事务层 | 数据链路层 |
| 作用范围 | 端到端,跨多个链路 | 仅相邻两个设备之间 |
| 典型类型 | Mem Read/Write、Cfg、Completion、Message | ACK/NAK、InitFC、UpdateFC、PM |
| 是否携带数据 | 可携带Payload | 不携带用户数据 |
| 对吞吐的影响 | 决定有效载荷效率 | 占用链路带宽,影响流控与重传 |
TLP是“运货的卡车”,DLLP是“调度和对讲机”。DLLP本身不运数据,但它占用物理层带宽。当链路误码率升高时,NAK和重传增多,DLLP比例上升,有效吞吐就会下降。因此,分析吞吐时不能只看TLP,还要关注DLLP的开销。
三、一次内存读的完整旅程
以CPU发起一次PCIe内存读为例,数据流如下:
- 事务层生成Mem Read TLP,包含Requester ID、Tag、地址和长度。
- 数据链路层为TLP添加序列号和LCRC,放入重传缓冲区,等待发送。
- 物理层进行加扰、编码和串行化,通过Lane发送到对端。
- 对端物理层恢复时钟和数据,数据链路层校验LCRC和序列号,正确则回ACK,错误则回NAK。
- 对端事务层解析请求,访问目标内存,生成Completion TLP(带数据)返回。
- 原端收到Completion后,按Tag匹配未完成请求,释放Tag和缓冲区。
这个过程中,Tag数量决定了同一时刻能有多少个未完成读请求。如果Tag耗尽,新的读请求只能等待,链路就会出现“空转”,吞吐无法打满。这是事务层最常见的瓶颈之一。
关键认知:PCIe吞吐不是单一指标,而是“有效载荷率 × 链路速率 × 链路宽度 × 协议效率”的综合结果。协议效率又受TLP开销、DLLP开销、ACK/NAK、流控Credit和重传共同影响。
四、常见误区与复盘要点
误区一:只看链路速率,忽略编码开销。Gen3及以上使用128b/130b编码,开销约1.5%;Gen1/Gen2使用8b/10b,开销高达20%。同样标称5GT/s,实际有效带宽差异明显。
误区二:认为DLLP不占带宽。DLLP虽然小,但在高误码或深流控场景下会频繁出现,累积开销不可忽视。
误区三:忽略Tag与Credit限制。很多“链路利用率上不去”的问题,根源不在物理层,而在事务层Tag不足或Credit耗尽。
复盘时建议按层排查:先看物理层链路是否训练到预期速率和宽度,再看数据链路层是否有大量NAK和重传,最后看事务层Tag和Credit是否成为限制。只有把三层串起来看,才能准确判断瓶颈位置。
# 查看PCIe链路速率与宽度(Linux示例)
lspci -vv -s 01:00.0 | grep -E "LnkCap|LnkSta"
# 典型输出关注点:
# LnkCap: Speed 16GT/s, Width x16 ← 设备能力
# LnkSta: Speed 16GT/s, Width x16 ← 当前实际状态
# 若LnkSta低于LnkCap,优先排查物理层与LTSSM