上一篇讲完 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 异常),先查时钟源质量,别怀疑网络。
六、两个容易踩的坑
- 别在软件层打时间戳。t2 这类接收戳如果由协议栈软件盖,从报文进网卡到盖戳,中间隔着驱动、中断、调度,抖动上百微秒——gPTP 的亚微秒精度直接泡汤。必须在 MAC/PHY 的 MII 出入点由硬件盖
- correctionField 别忘了减。报文每过一跳,
correctionField里都记着前序路径的延迟和驻留时间。算 offset 时减掉它才是真实偏移。刚接触 gPTP 的人用(t2 − t1)硬算,答案差出去几百 µs,就是这么来的
七、结语
把这篇压成三句话:
- 延迟 = 主时钟看全程 − 从时钟看全程,除以 2(干等间隔自动抵消)
- 偏移 = 到达读数 − 发出读数 − 路上耗时
- gPTP 默认用 P2P 逐跳测链路延迟,账记在
correctionField里
下一篇讲 correctionField 的记账细节:交换机在 Sync 上"过一手"到底耽搁了多久(驻留时间),这个数怎么量、怎么加、单位为什么是 2^-16 秒的缩放值——看完你就明白为什么说"交换机每转一手都在偷时间,而 gPTP 让它连本带利还回来"。
你们抓包时看到 offset 收敛要多久?晶振差的板子要多久?评论区聊聊。