2. CXL核心架构:CXL.io、CXL.cache、CXL.mem三大子协议详解、CXL与PCIe的关系
好,咱们直接进入正题。CXL这个协议,说白了就是一套「三合一」的通信方案。它把三种不同用途的协议打包在一起,分别解决不同的问题。我个人习惯把这三种协议想象成三个不同性格的快递员——一个负责慢悠悠地送大件包裹,一个负责快速送小件,还有一个负责帮你把邻居家的冰箱直接搬到你家里用。
这三个协议分别是:CXL.io、CXL.cache 和 CXL.mem。咱们一个一个拆开看。
2.1 CXL.io:基础通道,负责「慢活」
CXL.io 其实是基于 PCIe 的物理层和事务层改造而来的。你可以把它理解为 CXL 的「地基」。它主要负责设备发现、配置、中断、DMA 这些常规操作。
嗯,这里要注意:CXL.io 并不是全新的东西。它复用了 PCIe 的链路层和物理层,只是在事务层做了一些扩展。所以从电气特性上看,CXL 和 PCIe 5.0/6.0 是兼容的——你插在同一个插槽上,系统能自动识别。
核心要点:CXL.io 负责控制面通信,不参与数据面的一致性管理。它的延迟相对较高,但胜在稳定可靠。
我在项目中遇到过一个问题:有同事把 CXL.io 的流量和 CXL.mem 的流量混在一起分析,结果发现延迟抖动很大。后来我们才意识到,CXL.io 走的路径和 CXL.mem 完全不同——前者要经过 PCIe 的配置空间和中断控制器,后者直接走内存语义通道。所以,千万别把 CXL.io 当成高速数据通道用。
2.2 CXL.cache:加速器的「缓存窥探器」
CXL.cache 是干嘛的?说白了,它允许加速器(比如 GPU、FPGA、SmartNIC)直接窥探 CPU 的缓存行。你想想看,如果没有这个协议,加速器想访问 CPU 缓存里的数据,得先通过 DMA 把数据搬到自己的本地内存里,然后再处理——这中间多了一次拷贝,延迟就上去了。
CXL.cache 解决了这个问题。它让加速器可以直接向 CPU 发送「缓存行请求」,CPU 的缓存一致性引擎会响应这个请求,把数据直接推给加速器。整个过程对软件是透明的——你写代码的时候根本感觉不到数据是从 CPU 缓存里拿的。
我曾经调试过一个 AI 推理加速卡的项目。加速器需要频繁读取 CPU 侧的热点数据,如果用传统 DMA,每次都要走 PCIe 的 BAR 空间,延迟在 1~2 微秒。换成 CXL.cache 之后,延迟降到了 200 纳秒以内。嗯,这个差距是数量级的。
避坑指南:CXL.cache 的请求类型有三种:RdCurr(读当前值)、RdOwn(读并获取所有权)、RdOnce(读一次)。我建议你在设计加速器时,优先用 RdOnce,因为它不会触发缓存行的状态迁移,对 CPU 侧的性能影响最小。
2.3 CXL.mem:内存共享的「直通车」
CXL.mem 是 CXL 协议里最性感的部分。它允许加速器直接访问 CPU 的主存,也允许 CPU 直接访问加速器上的内存——而且这种访问是缓存一致性的。
什么意思呢?就是加速器可以把自己的本地内存「挂载」到 CPU 的物理地址空间里,CPU 访问这块内存就像访问自己的 DDR 一样。反过来,加速器也可以直接读写 CPU 的内存,不需要经过 DMA 描述符、不需要中断、不需要软件参与。
你想想看,这带来了什么?真正的内存池化。多个加速器可以共享同一块物理内存,数据不用搬来搬去。这在数据库、大数据、AI 训练场景下特别有用。
| 特性 | CXL.io | CXL.cache | CXL.mem |
|---|---|---|---|
| 主要用途 | 控制面、配置、中断 | 加速器窥探 CPU 缓存 | 内存语义访问、内存池化 |
| 延迟 | 微秒级 | 百纳秒级 | 百纳秒级 |
| 一致性模型 | 无 | 缓存一致性 | 内存一致性 |
| 典型场景 | 设备枚举、错误处理 | 加速器读 CPU 热点数据 | 内存扩展、共享内存 |
2.4 CXL 与 PCIe 的关系:不是替代,是进化
很多人问我:CXL 是不是要取代 PCIe?我的回答是:不会,也不应该。
CXL 是建立在 PCIe 物理层之上的。它用了 PCIe 的电气特性、链路训练、错误检测这些底层机制。你可以把 CXL 想象成 PCIe 的「应用层升级」——就像 HTTP/2 和 HTTP/3 都跑在 TCP 上,但协议语义完全不同。
具体来说,CXL 和 PCIe 的关系有几点:
- 物理层兼容:CXL 设备可以插在 PCIe 插槽上,反之亦然。系统通过链路训练时的 Vendor Defined Message 来协商是跑 CXL 模式还是 PCIe 模式。
- 事务层扩展:CXL 在 PCIe 的事务层之上增加了 CXL.cache 和 CXL.mem 的 flit(流控制单元)格式。PCIe 的事务层只处理 Memory Read/Write、Completion 这些标准事务。
- 仲裁机制不同:PCIe 是标准的树形拓扑,仲裁由 Root Complex 控制。CXL 引入了更灵活的「主机-设备」模型,设备可以主动发起缓存一致性请求。
注意:CXL 3.0 引入了交换机和多级拓扑,这已经超出了 PCIe 的范畴。但底层的物理层依然是 PCIe 6.0 的 PAM4 信令。所以,学好 PCIe 是理解 CXL 的前提。
我个人习惯把 CXL 和 PCIe 的关系总结成一句话:PCIe 是高速公路,CXL 是跑在这条路上的智能卡车——它知道怎么走最省油,还能自己装卸货。
2.5 三大子协议的协同工作
实际系统中,这三个协议是同时工作的。举个例子:
- 系统启动时,CXL.io 负责枚举设备、分配 BAR 空间、配置中断。
- 加速器开始工作后,CXL.cache 负责读取 CPU 侧的模型参数(这些参数在 CPU 缓存里)。
- 加速器处理完一批数据后,通过 CXL.mem 把结果直接写回 CPU 的主存,CPU 侧的应用直接读取,不需要拷贝。
你看,三个协议各司其职,互不干扰。但底层都跑在同一个物理链路上——这就是 CXL 的精妙之处。
我曾经在调试一个 FPGA 加速卡时,发现 CXL.cache 的请求总是超时。查了半天,原来是 CXL.io 的配置空间里有一个寄存器没设对,导致缓存一致性引擎没有正确初始化。所以,别以为 CXL.io 只是「跑腿的」,它出问题,其他两个协议也跑不起来。
总结:CXL.io 是控制面,CXL.cache 是缓存面,CXL.mem 是内存面。三者合一,才构成了完整的 CXL 协议栈。
这张图清晰地展示了 CXL 的分层结构。从上到下依次是:CPU、CXL 协议栈(三个子协议)、PCIe 物理层、加速器。三个子协议共享同一条物理链路,但逻辑上完全独立。
好了,这一章的内容就到这里。记住:CXL.io 是基础,CXL.cache 是加速器窥探缓存的利器,CXL.mem 是内存共享的核心。三者缺一不可。