PCIe基础:协议概述,各代速度与编码方式
大家好,我是你们这次实战课的老朋友。在开始折腾吞吐优化之前,咱们得先把地基打牢。PCIe这个协议,说白了就是芯片间的高速公路。你想想看,CPU、GPU、SSD、网卡,这些大家伙之间怎么传数据?全靠它。
我记得刚入行那会,老工程师跟我说一句话,我一直记到现在:“不懂PCIe协议分层,你优化吞吐就是瞎蒙。” 嗯,这话糙理不糙。今天我们就先把这个分层结构和各代速度的门道捋清楚。
1.1 协议核心架构:分层思维
PCIe协议栈,一共三层。从上到下,分别是事务层、数据链路层、物理层。每一层各司其职,又互相配合。
- 事务层:最上层,负责组装TLP包。读写请求、完成报文,都在这里封装。我习惯把它理解成快递公司的“打包车间”,决定包裹长什么样、送到哪。
- 数据链路层:中间层,负责可靠传输。它给TLP套上一层“保护壳”——DLLP。这层还管重传、流控、CRC校验。说白了,它保证你发的包,对方一定能收到。
- 物理层:最底层,负责把0和1放到物理线路上。串行化、解串行化、时钟恢复、电气特性,都归它管。这是真正在“路面”上跑车的部分。
为什么物理层这么重要?
因为吞吐优化的瓶颈,常常卡在物理层的编码效率和信号完整性上。你上层设计的再好,物理层跑不动,也是白搭。
1.2 每一代的速度与编码方式
这个我必须详细讲讲。数据是怎么在物理链路上传过去的?不是一股脑倒进去,而是以“字符”为单位,通过特定的编码方式,把数据变成能在线路上传输的比特流。编码效率直接决定了有效带宽。
1.2.1 Gen1 & Gen2:经典的8b/10b编码
Gen1,速率是2.5 GT/s(Giga Transfers per second)。为什么叫Transfer?因为每个时钟周期,差分对上传递一个“符号”,这个符号编码了8位用户数据加上额外的2位控制位。
Gen2,速率翻倍到5.0 GT/s,但编码方式没变,还是8b/10b。这意味着每传10个比特,只有8个是有效数据。有效带宽 = 理论速率 × 80%。
避坑指南: 我见过很多新手算带宽,直接拿GT/s乘链路宽度,以为就是吞吐。实际不是!
例子:Gen1 x4链路,理论带宽是 2.5 GT/s × 4 = 10 GT/s。但有效数据带宽 = 10 GT/s × 80% ≈ 8 Gb/s ≈ 1 GB/s。记住这个80%系数,否则性能预估会跑飞。
1.2.2 Gen3 & 之后的革命:128b/130b编码
到了Gen3,速率跳到8.0 GT/s。这时候PCI-SIG干了一件大事——把编码方式从8b/10b换成了128b/130b。好处很明显:编码效率从80%提升到了约98.46%(128/130 ≈ 98.46%)。
为什么会这样?说白了,8b/10b虽然能保证DC平衡和时钟恢复的可靠性,但开销太大。128b/130b通过更复杂的加扰器(Scrambler)和块对齐机制,同样保证了信号质量,但有效带宽大幅提升。
注意: 128b/130b编码并非完全没有开销。128个有效数据位加上2位同步头,总开销约1.54%。这比8b/10b的20%开销小太多了!
我当年在调Gen3链路时,跑吞吐测试发现死活上不去,后来才发现是误码率过高,物理层不断重传。这就是编码方式改变带来的挑战:对信号完整性要求更高了。
1.3 各代编码与有效吞吐一览
下面这个表格,我每次培训都要拿出来讲。它清楚地告诉你每个Gen到底能给你多少“真金白银”的吞吐。
| 代际 | 原始速率 (GT/s) | 编码方式 | 编码效率 | 有效数据带宽 (x1通道) (GT/s) |
|---|---|---|---|---|
| Gen1 | 2.5 | 8b/10b | 80% | 2.0 |
| Gen2 | 5.0 | 8b/10b | 80% | 4.0 |
| Gen3 | 8.0 | 128b/130b | 98.46% | ~7.88 |
| Gen4 | 16.0 | 128b/130b | 98.46% | ~15.75 |
| Gen5 | 32.0 | 128b/130b | 98.46% | ~31.51 |
从这个表你能看出来,Gen4 x16链路的理论有效带宽大约是15.75 × 16 = 252 GT/s,换算成GB/s大约是31.5 GB/s(假设单向)。这个数字就是你做吞吐优化时,物理层能给你的上限天花板。
1.4 链路宽度与聚合
还有一个关键概念:链路宽度(Lane Width)。一条PCIe链路可以由1、2、4、8、16个通道组成,分别记为x1、x2、x4、x8、x16。
每个通道都是独立的差分对,负责传一部分数据。它们可以并行工作。所以总带宽 = 单通道有效带宽 × 通道数。
嗯,这里要注意:多个通道之间是有偏差(Skew)的。物理层和链路层必须做去偏(Deskew)处理。我在调试一个FPGA上的Gen4 x8链路时,就遇到过因为PCB走线不等长,导致通道间偏差太大,链路直接降级到x4的情况。
实战小贴士:
在做吞吐压力测试时,一定要先确认链路实际协商出来的宽度和速率。用lspci命令(Linux)查看LinkCap和LinkSta,或者用PCIe Analyzer抓包看。不要想当然认为插了x16槽就一定是x16在跑。我曾经就被这个坑过,一块卡插在x16槽上,但因为机械结构问题,只连上了x8,吞吐直接腰斩。
1.5 需要留意的几个细节
- 数据速率 vs 有效吞吐: 永远记住,编码开销是第一个也是最大的损耗来源。Gen1/Gen2的20%开销是跑不掉的。
- 物理层还涉及其他开销: 比如有序集(Ordered Sets)、链路训练状态机(LTSSM)的状态切换,这些都会占用物理层的带宽。
- 链路训练与稳定性: 每次上电或复位,PCIe都要经过复杂的链路训练过程。这个过程如果不稳定,可能导致降速或降宽。
好了,这一章的基础铺垫就到这。记住PCIe的三层架构,记住各代的速率和编码效率。你想想看,这些数字和规律,就是后面我们做优化时,用来衡量“损耗”和“天花板”的尺子。没有这把尺子,你都不知道自己优化得到底好不好。