上一篇讲完 BMCA:全网选出了唯一的 GM,同步树也建好了。这篇讲最核心的问题——从时钟怎么算出"我的表比 GM 快多少"以及"报文在路上花了多久"。

答案藏在四个时间戳里。这篇把公式推一遍,再代入数字验算,保证你看完能自己复现。

一、先记住四个时间戳

以最经典的 E2E(端到端)Delay_Req 机制为例,一次同步来回涉及四个时刻:

记号谁盖的戳什么事件
t1主时钟Sync 报文发出的时刻(精确值)
t2从时钟Sync 报文到达本地的时刻
t3从时钟Delay_Req 报文发出的时刻
t4主时钟Delay_Req 报文到达主时钟的时刻

注意 t1 的精髓:为了把精确的发送时刻量出来,两步法(two-step)里 Sync 只负责"发",精确的 t1 由紧随其后的 Follow_Up 报文捎带。一步法(one-step)则把 t1 直接塞进 Sync 里发。

为什么主流都是两步法?在 MII 口给正在发出的报文盖一个"精确到 ns 的出发戳"有硬件难度,而 Follow_Up 是随后从容发出的——时间充裕,盖得准。车载 gPTP 默认两步法。

二、两个公式:先讲直觉,再推形式

2.1 延迟怎么算

直觉:主时钟视角看,从 Sync 发出(t1)到 Delay_Req 收到(t4),耗时 = 去程延迟 + 从时钟干等的间隔 + 回程延迟;从时钟视角看,从 Sync 收到(t2)到 Delay_Req 发出(t3),只包含干等的那段。两者相减,干等抵消,剩下两倍链路延迟:

d = ( (t4 − t1) + (t2 − t3) ) / 2

这里 d 就是平均路径延迟。注意隐含假设:去程和回程延迟相等(路径对称)——这是所有 PTP 类协议的共同前提,链路的物理对称性一般成立,不对称误差直接进 offset。

2.2 偏移怎么算

直觉更简单:Sync 离开主时钟时读数是 t1,到达本地时读数是 t2。这多出来的 (t2 − t1) 里,一部分是路上花的 d,剩下就是我的表快了/慢了:

offset = (t2 − t1) − d

offset > 0 表示从时钟走快了,servo 该把它往慢拧;offset < 0 则相反。

把两个公式合起来,得到一个不显含 d 的形式,工程上常用:

offset = ( (t2 − t1) − (t4 − t3) ) / 2

三、代入数字,验算一遍

光看公式不踏实,跑个数。设:

  • 链路平均延迟 d = 500 ns
  • 从时钟比主时钟快 2 µs(offset = +2 µs)
  • 从时钟收到 Sync 后,干等 1 ms 才发 Delay_Req

四个戳:

戳时钟数值
t1主100.000000000 s
t2从100.000002500 s
t3从100.001002500 s
t4主100.001001000 s

验算:

d = ((t4 − t1) + (t2 − t3)) / 2
  = ((1001.0 µs) + (−1000.0 µs)) / 2
  = 500 ns                              ✓ 与设定一致

offset = (t2 − t1) − d
       = 2.5 µs − 0.5 µs
       = +2 µs                           ✓ 与设定一致

offset = ((t2 − t1) − (t4 − t3)) / 2
       = (2.5 µs − (−1.5 µs)) / 2
       = +2 µs                           ✓ 两条路径殊途同归

两条公式路径给出同一个答案,说明推导自洽。记住这个例子,比记公式管用。

四、gPTP 的默认姿势:P2P 链路延迟测量

上面是 E2E 机制——端到端测一整条路径的延迟。但 gPTP(802.1AS)的默认机制是 P2P(Peer-to-Peer,逐跳),报文换成三个:

报文方向作用
Pdelay_Req本端口 → 链路邻居测量这条链路的延迟
Pdelay_Resp邻居 → 本端口回应,带上邻居的发时刻 t3
Pdelay_Resp_Follow_Up邻居 → 本端口两步法时补发精确的 t3

四个戳的对应关系:t1 = 本端发 Pdelay_Req,t2 = 邻居收到,t3 = 邻居发 Resp,t4 = 本端收到 Resp。公式和 E2E 完全一样,只是语义从"端到端路径"缩到了"这一段链路"。

P2P 的工程价值在 BC 级联场景:

  • 每个端口只测自己连着的那段线,测出的链路延迟逐跳报给上层
  • 交换机转发 Sync 时,把上下游的链路延迟 + 自己内部的驻留时间,全部累加进 correctionField
  • 从时钟拿到 Sync 时,用 (t2 − t1 − correctionField) 直接得到相对 GM 的偏移——不需要自己再发 Delay_Req 测全程

E2E 是"末端一次量全程",P2P 是"每跳各量各段、账记在报文里"。级联跳数多了,P2P 的误差可控性更好——这也是 802.1AS 选它当默认的原因。下一篇讲 correctionField 怎么记账。

五、对表现场:offset 拿到手之后干什么

算出 offset 只是第一步,把表调过来才是同步的完成。这里有个关键区分:

调整对象含义特点
相位(phase)表显示的"数值"直接 ±offset立竿见影,但表的走速没变,过会儿又飘
频率(rate)把晶振的倍频/分频比微调,让表走得和 GM 一样快起效慢,但能根治

真实 servo 是 PI 控制器(比例 + 积分):比例项快速吃掉相位差,积分项慢慢修正频率差(体现为 rateRatio 和 neighborRateRatio,gPTP 报文里都有字段承载)。表现就是:

  • 同步刚建立时,offset 有个收敛过程,几十秒到几分钟不等
  • 收敛后 offset 在几十 ns 量级抖动,晶振越好抖得越小

排查经验:抓包看 offset 长期单向漂移 → 大概率是本地晶振频偏没被伺服纠正(rateRatio 异常),先查时钟源质量,别怀疑网络。

六、两个容易踩的坑

  1. 别在软件层打时间戳。t2 这类接收戳如果由协议栈软件盖,从报文进网卡到盖戳,中间隔着驱动、中断、调度,抖动上百微秒——gPTP 的亚微秒精度直接泡汤。必须在 MAC/PHY 的 MII 出入点由硬件盖
  2. correctionField 别忘了减。报文每过一跳,correctionField 里都记着前序路径的延迟和驻留时间。算 offset 时减掉它才是真实偏移。刚接触 gPTP 的人用 (t2 − t1) 硬算,答案差出去几百 µs,就是这么来的

七、结语

把这篇压成三句话:

  1. 延迟 = 主时钟看全程 − 从时钟看全程,除以 2(干等间隔自动抵消)
  2. 偏移 = 到达读数 − 发出读数 − 路上耗时
  3. gPTP 默认用 P2P 逐跳测链路延迟,账记在 correctionField 里

下一篇讲 correctionField 的记账细节:交换机在 Sync 上"过一手"到底耽搁了多久(驻留时间),这个数怎么量、怎么加、单位为什么是 2^-16 秒的缩放值——看完你就明白为什么说"交换机每转一手都在偷时间,而 gPTP 让它连本带利还回来"。

你们抓包时看到 offset 收敛要多久?晶振差的板子要多久?评论区聊聊。

TSNgPTP802.1AS时间同步公式推导