4. 端到端延迟定义:传输延迟、协议延迟、队列延迟、抖动等指标

做 CXL 延迟测量这些年,我经常被问到一个问题:你到底在测什么东西?大家嘴上都说“延迟”,但每个人脑子里想的数字其实不一样。有的人盯着链路传输时间,有的人关心协议握手成本,还有人被队列阻塞折磨得够呛。

我个人习惯先把端到端延迟拆成四个基本成分:传输延迟、协议延迟、队列延迟和抖动。这四个成分加在一起,才是你真实体验到的延迟。今天我们就挨个讲清楚。

4.1 传输延迟

这个最好理解。物理信号在走线、连接器、PCB 上传播需要时间。电信号在铜线里大约 5 ~ 6 ns/m,光信号在光纤里大约 4.9 ns/m。CXL 通常走的是高速串行差分对,线长从几厘米到几十厘米不等。

我记得有一次在调试一个 CXL 1.1 的原型板,链路训练总是超时。后来拿眼图扫了一遍,发现通道长度差了接近 20 cm。那 0.1 ns 的额外传播时间,直接让协议层误判了时序窗口。所以传输延迟虽然值小,但你不能忽略它。

传输延迟 ≈ 物理介质长度 × 信号传播速度 + 连接器/过孔等效延迟
实际测量时,建议用 TDR(时域反射计)扫一下走线长度,再把计算值和仿真结果交叉验证。

4.2 协议延迟

协议延迟是 CXL.cache 请求从发起到完成,协议状态机消耗的时钟周期数。这包括:

  • 请求打包:把 CPU 侧的读/写请求封装成 CXL 协议报文。
  • Link 上传输:经过 FLIT(流量控制单元)格式化、CRC 计算、重传缓冲区。
  • 目标端解包:把报文还原成内存/设备侧的内部请求。
  • 响应打包/解包:同理。

说白了,协议延迟就是软件和硬件之间来回“翻译”的成本。你想想看,每多一层封装,就多几个额外周期。CXL.cache 的协议本身已经尽力压缩了,但 Retry 机制、Credit 交换、缓存一致性状态的切换都会增加额外开销。

我在项目中遇到过一种情况:设计团队为了省一个寄存器级,缩短了协议状态机的关键路径,结果导致 hold 违规,整个子系统的协议窗口垮掉。最后回头老老实实加了一拍 pipeline,协议延迟涨了 1 ns,但 timing 收敛了。所以这里不能一刀切追求最小延迟,要 tradeoff。

子阶段 典型延迟(@ PCIe 16 GT/s) 说明
请求封装 ~10 ns 包含报头组装、CRC 插入
FLIT 序列化 ~4 ns 按 66/64b 编码,加上符号位
响应解包 ~8 ns 解码、有效性检查
Cache 状态更新 ~5 ns MESI 状态机跳转
协议延迟受链路宽度和速率影响很大。如果链路降宽(比如 x16 降 x8),序列化时间翻倍。我曾经看到有人把 CXL 挂到 Gen4 x4 上,协议延迟直接爆到 80 ns 以上,毫无优化空间。

4.3 队列延迟

这个最容易被人忘记,也最致命。队列延迟 = 请求在缓冲区里等待被处理的时间。CXL.cache 路径上有多个队列:

  1. 发送队列:主机端发出请求前的排队。
  2. 接收队列:设备端收到请求后的排序。
  3. 重排序缓冲区(Reorder Buffer):等待所有依赖请求完成。
  4. 回放队列:触发重传时的暂存。

队列延迟的主要来源是 背压(backpressure)。当下游处理速度跟不上上游发送速度时,队列开始堆积。而队列一旦变深,延迟就会迅速恶化。你想想看,一个请求本来只花 20 ns 处理,结果前面排了 100 个请求,那延迟直接变成 2 μs。

我在项目中遇到过最头疼的 case:一个 CXL Type-2 设备在做 burst 写入时,因为内部 SRAM 的 bank 冲突,导致读回放队列在短时间内增长了 30 倍。事后分析发现,根本不是链路问题,是队列调度策略太 naive。

队列延迟 = 队列深度 × 平均服务时间
想降低队列延迟,要么减少深度,要么缩短服务时间。但深度太小又会引起丢包重传,这是个平衡。

4.4 抖动

抖动不是平均延迟,而是延迟的变化量。为什么需要单独列一个指标?因为对于实时性要求高的场景(比如 CXL 用于加速器缓存一致性),平均延迟达标了,但抖动太大,依然会导致超时或者乱序。

抖动的来源:

  • 链路层纠错重传:CRC 错误后重发一个 FLIT,增加随机耗时。
  • Credit 回传不对称:流控 Credit 返回延迟不稳定。
  • 仲裁冲突:多个虚拟通道(VC)争用物理链路。
  • 电源噪声 / 时钟抖动:物理层面引入的随机抖动。

我个人测量抖动喜欢用直方图 + 分位数。只看平均值会骗人,99.9% 分位延迟才是真实体验。

测量抖动时,建议采集至少 100 万个样本,然后绘制 CDF 曲线。95% 分位和 99.9% 分位的差值就是你的抖动极端幅度。如果这个差值超过平均延迟的 50%,你的系统一定有个别诡异路径没有覆盖到。

4.5 延迟构成图:一眼看懂端到端的全局

我们把上面四个成分放在一张图里。你从发起到完成,每一笔 CXL.cache 请求都经过这些阶段。注意,抖动不是单独一个模块,它是对整条路径延迟的不确定性度量,所以我用虚线包围表示。

端到端延迟分解结构图 端到端延迟 = 传输 + 协议 + 队列 + 抖动 端到端延迟 (Latency) 从请求发起至响应返回的完整时间 传输延迟 信号物理传播 协议延迟 状态机 & 封装 队列延迟 等待 & 背压 抖动 延迟变化量 关键结论 • 四个成分相互独立又相互影响:队列延迟会放大抖动,抖动又会导致重传增加协议延迟。 • 测量时必须区分每一个成分,才能精准定位瓶颈。 抖动影响全局

4.6 四个指标如何协同评估

最后给你一个我常用的测量清单。每次拿到新平台,我都按这个顺序走一遍:

  1. 测传输延迟:用回环模式发一个最小包,去掉协议开销,只看物理往返。如果超过理论最小值太多,查 PCB 走线。
  2. 测协议延迟:发一个无数据竞争的简单请求(比如读一个干净缓存行)。把传输延迟减掉,剩下的就是协议状态机耗时。
  3. 测队列延迟:逐步加大请求并发度,观察平均延迟曲线。当延迟开始非线性上升时,就是队列开始生效了。记录那个拐点。
  4. 测抖动:固定并发度(比如 8 个请求),采集 100 万笔延迟样本,看 99.9% 分位与 50% 分位的差值。
注意:如果要对比两个配置的延迟,必须保证采样条件一致——同一组 CXL 地址、同一链路速率、同一背压状态。否则你比较的是两个不同的系统画像,没有意义。

嗯,这四个指标搞清楚了,后面我们聊优化才有根基。你想想看,如果连瓶颈在哪一层的都不知道,谈什么优化?