第一节: 简介

在过去的几十年里,计算机系统已经从相当孤立的单元演变为高度复杂的分布式系统,通过各种类型的通信媒体相互连接。这种演变可以在许多领域观察到,例如工业自动化和测试与测量。随着系统每天变得越来越复杂和分散,为这些系统保留一个精确的时间源是一项具有挑战性的任务。在分布式环境中运行的应用程序需要将事件、数据或操作与某个时刻关联起来,以便像一个更大的虚拟系统一样工作。
精确时间协议(PTP)设计用于在分布式环境中实现非常精确的同步,例如在不可靠和不确定网络上通信的节点之间。虽然Linux正在成为嵌入式系统的主流操作系统,但对IEEE 1588的支持只是缓慢地引入主流内核。我们认为,更好的PTP支持,完全集成到操作系统中,是必要的,这样所有应用程序都可以从更精确的计时中获益。
IEEE 1588团体一段时间以来一直专注于诸如PTP时钟的准确性、网络基础设施对可实现精度的影响,或提高节点之间的同步精度等问题。大多数PTP解决方案纯粹从IEEE 1588的角度考虑该问题,重点是如何保持PTP时钟与主时钟的高精度同步。到目前为止,很少有人关注在系统上运行的应用程序,而如何将操作系统时钟与PTP时钟同步等问题也被完全抛在了一边。在我们看来,这是一个必须解决的关键问题,以确保IEEE 1588标准在现实世界中得到更广泛的接受。今天的大多数应用程序都不知道PTP时钟,并使用标准API(如time或gettimeofday)从系统时钟获取时间信息。重要的是以可接受的精度将Linux系统时钟与PTP时钟同步,而不需要重写或修改在操作系统上运行的应用程序。
本文介绍了我们将Linux系统时钟与PTP时钟同步的工作。首先,我们回顾了以前在这方面所做的工作。接下来,我们提出了一种同步系统时钟的解决方案。我们介绍了使用我们的方法获得的结果。最后,我们讨论了结论,并提出了今后要做的步骤。

第二节 背景以及之前的工作

NTP之父大卫·米尔斯可能是最早努力将系统时钟与外部时间源同步的人之一。尽管他提出的一种新的精确计时内核模型已有近二十年的历史[1][2][3],但他的许多方法和结果在我们今天拥有的新硬件环境中仍然非常相关。
由于NTP不需要硬件时间戳,作为纯软件解决方案,它直接同步内核时钟并调节系统时钟的频率。Mills描述了使用每秒脉冲(PPS)输入或外部时钟和振荡器来提高系统时钟精度和稳定性,仅受操作系统抖动和同步源稳定性的限制。
将IEEE 1588支持引入GNU/Linux操作系统需要在内核中设计和集成两个重要服务,即在硬件层控制硬件时钟和数据包时间戳。2009年2月,Patrick Ohly在Linux版本2.6.30中引入了对硬件辅助时间戳的支持,并发布了使用拟议API的ptpd程序的修改版本[4]。2010年,如[5]所述,提出了支持PTP硬件时钟(PHC)的Linux内核框架,并提供了实验证据,证明了该解决方案的合理性。该框架已经过了几轮
对邮件列表进行了审查,并收到了积极反馈。PHC补丁系列的后台支持[6]被合并到内核版本2.6.39中,完整的PHC支持预计将出现在版本3.0.0中。虽然时间戳和PHC支持已成功引入内核,但仍需要解决一个问题,即如何准确地将Linux内核与非常精确的PTP时间源同步。图1给出了Linux PTP硬件时钟子系统的图示。我们将回到这个图以及第四节中围绕系统时钟的问题。
Patrick Ohly[7]提出了两种方法来实现这一目标。第一种称为“辅助系统时间”,第二种称为“两级PTP”,第二种方法与我们的
提出的解决方案有些相似,我们将在下面进行详细讨论。
Ohly的第一个解决方案仅使用PTP硬件时钟作为时间戳,向时间戳添加偏移量纠正PHC和系统时间之间的差异。
基本思想是直接从ptpd程序控制系统时钟,但在以太网设备驱动程序中跟踪两个时钟之间的差异。由于两个时钟以不同的频率运行,它们的偏移会漂移,因此必须定期测量。每次测量读取一次PHC和两次系统时钟,一次在PHC读数之前,一次在PHC读数之后。为了计算时间偏移,Ohly对十个测量值的序列进行平均,首先通过消除25%的数据点来消除异常值。
Ohly得出了平均数,Ohly的“辅助系统时间”的实现与硬件时间戳支持合并到Linux内核中,名称为timecompare。
这种方式的重大问题在于重复次数是硬编码到每个独立的以太网驱动中的(现在好像不需要硬编码到驱动中,不是通过phc2sys的参数选项进行调整吗?),而想要获得好的效果实际次数取决于整个系统,测量在内核空间中执行,以避免中断,所以调整重复次数需要重新编译内核。一般来说,不可能选择一套驱动程序适用于所有不同类型系统的参数。
时间比较法在假设方面进一步存在缺陷:PHC时间读数恰好发生在两次系统时间读数之间。虽然这可能适用PHCs
集成到片上系统或通过快速总线连接,这一假设通常不成立。
我们尝试比较Intel ARM IXP425的系统时间和国家半导体公司DP83640 PHY的PHC时间,结论是“timecompare”方法不稳定。在这个平台上,读取PHC需要通过MDIO总线时钟为2.5 MHZ。每个MDIO总线事务至少需要64个总线周期。一次读取需要五个事务使用PHY寄存器。我们的实验表明,一次读取操作的延迟约为170-190µs,但PHC时间值在第一次读取时锁定在PHY中。
显然,假设PHC时间戳发生在两次系统时间戳的中间仅适用于某些特殊类型的硬件。此外,需要将重要的同步参数硬编码到以太网驱动中,使得这种方式更难正确调整系统。由于参数与驱动程序无关,而是与整个系统有关,在我们看来,将它们硬编码到内核是错误的方法。
Ohly的第二个想法,即“两级PTP”方法,有点类似于使用PPS将系统时钟同步为PHC时间。该方法建议使用PTP堆栈的两个实例。第一个实例通过网络将PTP硬件时钟同步为PTP主机时间,第二个实例将系统时间调整为PHC。Ohly假设缺点
这种解决方案的缺点是增加了系统的复杂性。在我们看来,这个想法值得一试,但我们同意在同一个节点上运行两个PTP软件实例是相当不切实际的。

第三节 linux系统时延

曾考虑将PTP硬件时钟作为时钟源和时钟事件设备的组合提供给Linux内核,但最终被拒绝,如[5]所述。虽然这种方法将消除内部PHC系统同步的需要,但很明显,某些各种硬件时钟不能以这种方式使用,因为它们太慢,例如通过MDIO总线寻址的PHY芯片。
相反,PHC子系统依赖PPS子系统将Linux系统时间与PTP时钟同步。我们支持这个想法,认为同步对于大多数应用程序来说,精度足够高,而不需要重写它们以使用PTP时钟。时间要求更高的应用程序始终可以直接使用新的PTP接口。
中断和调度延迟决定了睡眠任务切换到运行模式的速度。如果系统时钟与PTP时钟的同步精度远优于系统的调度延迟,我们认为实现的同步对于大多数应用来说足够好。为了支持这一说法,我们简要分析了当前的Linux内核中断和调度延迟。
自2.4版以来,Linux内核调度程序得到了极大的改进。在过去,调度器对所有处理器都有一个执行队列,导致O(n)调度复杂性。新的调度程序被改进为具有O(1)复杂性,每个处理器都有自己的运行队列[8]。减少内核和用户空间延迟是一项持续的工作。抢占RT分支已部分合并到主线Linux中,从而提高了实时性能。
不过,根据内核版本和硬件架构,Linux表现出毫秒范围内的典型调度延迟。
为了说明当前Linux的性能,我们讨论了在不同硬件平台上使用cyclictest程序的测量。基于Linux PREEMPT RT内核开发工作,该程序从应用程序的角度测量总体系统延迟。通过在特定持续时间内重复生成CPU并与实际阻塞时间进行比较,cyclictest测量用户空间程序的总体调度延迟。
表一显示了我们的延迟测试结果。我们在运行Ubuntu内核2.6.32-29-generic-pae的IBM Lenovo W510和运行内核2.6.39的飞思卡尔P2020RDB PowerPC平台上,使用命令行参数i 10000-l 100000运行了cyclictest。测试在重负载和机器闲置的情况下运行。无CPU负载时的平均调度延迟不超过100µs。虽然无负载时的最小值达到5-10µs,但绝对最大值可能超过1s。
其次,尤其是在运行缓存抖动程序时。尽管延迟测量值因硬件架构、内核版本和系统负载的不同而有很大差异,但我们发现我们的测量值与其他人报告的结果基本一致[9][10][11]。
我们可以得出结论,如果PTP和系统时钟之间的同步精度保持在100µs以内,这应该足以为在系统上运行的大多数应用程序提供准确的时间信息。

第四节 同步linux系统时钟

Linux PTP硬件时钟子系统的框图如图1所示。
从顶部开始,来自PHC的时间戳数据包通过SO_TIMESTAMPING套接字选项提供给PTP协议栈。PTP协议栈计算适当的校正值,并使用标准POSIX时钟功能调整PHC。同时,来自PHC的PPS信号由内核在中断服务例程(ISR)中加时间戳,并通过PPS的标准NTP接口提供给用户空间程序。我们研究的重点是该程序的详细操作。
图2a描述了一个典型的时钟伺服拓扑,用于将PHC和Linux内核时钟同步到网络的PTP主机。该拓扑表示PHC和内核时钟驻留在两个不同硬件组件上的系统,例如网卡和CPU,由两个单独的振荡器驱动。这样的构造通常是在标准PC上找到。

系统上运行的PTP实现确定主时钟和从时钟之间的时间偏移o(t)。
第一个时钟伺服旨在通过使用控制信号u(t)调整PTP时钟来最小化该时钟偏移。一旦PHC与主时钟正确同步,任务就是使用精确的时间信息来调节Linux系统时钟。
在第二节中,我们讨论了估计时钟偏移e(t)值的两种基本方法。可以读取两个时钟的时钟值并计算时钟偏移,也可以使用PHC产生信号的PPS时间戳。在这两种情况下,由于这些测量基本上是软件时间戳,它们受到第三节中讨论的系统延迟的干扰。n(t)表示这些延迟引入的测量噪声。我们的实验表明,该噪声n(t)可能比实际时钟偏移e(t)高一个数量级,对控制回路的性能产生负面影响。
例如,图3显示了在重载情况下,飞思卡尔P2020RDB上获取的PPS时间戳的直方图。通过将系统时间设置为PHC时间,然后观察PHC的PPS偏移来收集这些数据,从几分钟后的系统时钟可以看出。根据系统活动,ISR可能延迟十几微秒或更长时间。即使这些特定数据是在不现实的重载下获取的(请参阅第五节中的脚本),但我们仍然观察到在系统空闲时出现类似的延迟,尽管发生频率要低得多。

嵌入式系统的设计者通常不受图2a架构的约束。对于这些系统,我们提出了一种不同的方法,可以更好地实现PHC和系统时钟之间的同步。

飞思卡尔P2020等片上系统设备集成了CPU和PTP硬件时钟到同一芯片上,从同一个振荡器操作CPU时钟和PHC。在PHC位于CPU外部的其他设计中,可以使用公共振荡器来驱动PHC和CPU(以及内核)时钟。
图2b显示了一种配置,其中PHC和内核时钟都由同一个振荡器驱动。如图2a所示,PTP协议栈导出o(t),即从时钟和主时钟之间的偏移量。再次使用时钟伺服来调整PHC。控制回路稳定且PHC对齐后,对于主时钟,仅调整控制信号u(t)以校正本地时钟的漂移。振荡器频率的变化现在以相同的方式影响PHC和内核时钟,并且维持同步所需的控制信号对于这两个时钟是相同的。因此,我们不仅直接将u(t)馈送到PHC,而且还使用它来调整内核时钟。由于我们无法同时为两个时钟设置新的调谐值,因此引入了时间延迟τ,但由于该时间延迟通常比控制回路的采样时间(PTP同步速率)小,因此可以忽略。
由于这两个时钟由同一个振荡器驱动,并由相同的信号u(t)调谐,因此它们是同步的。第二个控制回路仅用于消除时钟之间的恒定相位偏移。尽管该伺服的控制器输入e(t)+n(t)受到测量噪声的影响,由于系统延迟,控制器必须只校正τ的小影响。因此,可以通过使用适当的滤波器来消除测量噪声,对其进行缓慢调谐。

第五节

我们进行了一对实验,以确定通过使用PPS,系统时钟与PHC的同步程度。在这些测试中,我们使用了飞思卡尔P2020RDB和Meinberg Lantime M600主时钟。为了测试如图2a所示操作PHC和系统时钟的情况,我们使用了ptpd[12]的一个版本,该版本已扩展为使用PHC接口。我们将该程序作为纯从普通时钟运行,并通过网络与PTP主时钟同步。与PTP主机同步自然会迫使PHC偏离系统时钟。
为了调节系统时钟,我们编写了一个实现比例积分(PI)控制器的简单程序。时钟伺服的传递函数由下式给出:

这里,U(z)和E(z)分别是应用于时钟和PHC与系统时钟之间的偏移的频率调整的z变换。通过极点配置发现系数kp=0.0784和ki=0.0016在我们的系统上显示出良好的控制器性能。这个采样时间为1秒。除了读取PPS时间戳和调整系统时钟外,该程序还检查实际时钟偏移,使用第二节中讨论的时间比较方法。我们在两种不同的系统负载下运行了测试。为了确定绝对最坏情况下的同步行为,我们首先在极端系统负载下运行测试。然后,为了与其他各种已公布的结果比较,我们在更轻的负载下进行了测试。
为了研究系统负载的影响,我们让下面的脚本在测试期间运行,这将产生一个无休止的序列,大约5分钟的极端负载,然后是5分钟的空闲时间。

三小时周期测试的结果如图4所示。顶行显示收到的PPS时间戳,底行显示时间比较测量的结果(phc时间和系统时间比较)。负载脚本的周期性干扰清晰可见,有时ISR延迟高达约30微秒。重系统负载的明显影响是约6微秒的时间误差(轻负载时误差是-4,重负载时误差是-10)。

为了评估图2b的伺服方案,我们使用混合ptpd版本重复测试,更改为同时调整PHC和系统时钟。通过这种方式,单个程序ptpd实现了PTP堆栈和PPS伺服。
乍一看,合成伺服方案的性能似乎与第一种方案大致相同。然而,仔细观察会发现一些性能差异。图5显示了合成测试的细节,与第一次测试的细节进行比较。,注意,图6显示了图4中较低轨迹的详细视图。当时钟同步时,由于系统负载引起的总峰-峰时间误差减少约1微秒。此外,在没有系统负载的情况下(在图5上半部分的偏移期间),曲线看起来更平滑。

考虑到第三节中讨论的典型Linux调度延迟,这里实现的同步性能似乎是可以接受的。从这些实验中可以看出,使用从PTP硬件时钟产生的PPS同步到系统时钟可以提供良好的结果。即使在极端系统负载下,诱导漂移也不超过6微秒。
图7和图8分别显示了在轻系统负载下有合成方案和没有合成方案的情况下的同步性能。将其与图5和图6进行比较是有益的(图5和图6是重负载的情况)。同样,当时钟被同步化时,峰-峰时间误差更小,轨迹总体上更平滑。这些结果与使用软件时间戳的各种其他方法进行了比较。Correl[12]报告了在“相当繁忙”的m68k CPU上10µs内的同步。在“非常轻的系统负载”下,RADclock[13]方法也报告了类似的结果。我们的实验清楚地证明了基于软件时间戳方法的同步是如何受到系统负载的显著影响的。在我们看来,没有准确说明系统负载的测量报告可能是乐观的,应该以健康的怀疑态度看待。

Linux系统时钟与PTP硬件时钟的同步非常重要,因为它将使所有应用程序受益于更精确的PTP时间源。此处提供的解决方案不需要
重写应用程序,而是直接使用PTP时钟。我们的工作重点是同步时钟,我们提出了两种时钟伺服拓扑来实现这一点。使用两个不同振荡器的伺服架构可以用于运行Linux的任何设备。嵌入式系统和系统芯片设计可以利用改进的架构,它具有一个公共频率源。在这种情况下,时钟是同步的,第二个控制回路只需要消除PTP硬件时钟和系统时钟之间的小偏移。
测试还证明了该概念的合理性。我们认为,同步精度足以在广泛的应用中使用。该解决方案还具有使用标准内核组件(PHC和PPS子系统)的优势,无需修改或重新编译内核。
虽然现有的Linux时间比较方法仍然有助于评估同步实验,但与成熟的PPS伺服方法相比,它似乎是一种没有吸引力的临时解决方案。我们方案的一个最大优点是,它将时钟伺服程序保留在用户空间中。通过这种方式,系统管理员和最终用户可以轻松调整伺服算法以满足其特殊需求。
然而,还有更多的工作要做。内核2.6.38中增加了支持将PPS时间戳直接输入内核中的NTP伺服(所谓的“硬PPS”方法)。比较这种内核空间方法与我们的用户空间方法的同步性能会很有趣。虽然我们第一次实验的结果很有希望,但我们仍然希望测试更广泛的硬件和软件组合。
我们预计,我们的解决方案将对开源社区内PTP的接受产生积极影响,使IEEE 1588成为GNU/Linux操作系统的标准同步选项。只有将PTP解决方案完全集成到操作系统中,我们才能为绝大多数Linux设备和应用程序获得IEEE 1588的全部好处。


这两种系统时间同步的方法都在ts2phc中有使用,笔者将ts2phc使用这两种方法运行,同时使用testptp来测试系统时间和phc时间的差值,发现使用pps来矫正系统时间效果确实更好写。
这篇论文比较老了,设备和内核都在往前演进,有些地方可能不符合当前的情况,二者的优劣势需要以当前的情况再进行审视。

Logo

更多推荐