【发布时间】:2011-04-01 04:59:22
【问题描述】:
您能解释一下clock_gettime() 在 Linux 上返回的 CLOCK_REALTIME 和 CLOCK_MONOTONIC 时钟之间的区别吗?
如果我需要计算外部源生成的时间戳与当前时间之间的经过时间,哪个更好?
最后,如果我有一个 NTP 守护程序定期调整系统时间,这些调整如何与 CLOCK_REALTIME 和 CLOCK_MONOTONIC 交互?
【问题讨论】:
标签: linux
您能解释一下clock_gettime() 在 Linux 上返回的 CLOCK_REALTIME 和 CLOCK_MONOTONIC 时钟之间的区别吗?
如果我需要计算外部源生成的时间戳与当前时间之间的经过时间,哪个更好?
最后,如果我有一个 NTP 守护程序定期调整系统时间,这些调整如何与 CLOCK_REALTIME 和 CLOCK_MONOTONIC 交互?
【问题讨论】:
标签: linux
CLOCK_REALTIME 代表机器对当前挂钟时间的最佳猜测。正如Ignacio 和MarkR 所说,这意味着CLOCK_REALTIME 可以随着系统时钟的变化(包括NTP)前后跳转。
CLOCK_MONOTONIC 表示自过去某个任意固定点以来经过的绝对挂钟时间。它不受系统时钟变化的影响。
如果您想计算在一台机器上观察到的两个事件之间的经过时间,而不需要重新启动,CLOCK_MONOTONIC 是最佳选择。
请注意,在 Linux 上,CLOCK_MONOTONIC 不会测量挂起所花费的时间,尽管根据 POSIX 定义它应该这样做。您可以使用特定于 Linux 的 CLOCK_BOOTTIME 作为在挂起期间保持运行的单调时钟。
【讨论】:
CLOCK_MONOTONIC 会是最佳选择吗?例如Patriot Missile System
Robert Love 的书LINUX System Programming 2nd Edition,在第 11 章开头,第 363 页专门解决了您的问题:
单调时间源的重要方面不是当前 值,但保证时间源是严格线性的 增加,因此对于计算时间差很有用 两次采样之间
也就是说,我相信他假设这些进程在同一操作系统实例上运行,因此您可能希望运行定期校准以能够估计漂移。
【讨论】:
CLOCK_REALTIME受NTP影响,可以前后移动。 CLOCK_MONOTONIC 不是,并以每滴答一滴的速度前进。
【讨论】:
System.nanoTime() 使用 CLOCK_MONOTONIC 并且可以测量 1000ns 或更短的 durations。也许您正在考虑系统时间,有时会限制为毫秒?
除了Ignacio's answer,CLOCK_REALTIME 可以向前跳跃,偶尔向后跳跃。 CLOCK_MONOTONIC 两者都不做;它只是继续前进(尽管它可能会在重新启动时重置)。
一个健壮的应用程序需要能够容忍CLOCK_REALTIME 偶尔向前跳跃(也许非常偶尔向后跳跃,尽管这更像是一种边缘情况)。
想象一下当您暂停笔记本电脑时会发生什么 - CLOCK_REALTIME 会在恢复后向前跳,CLOCK_MONOTONIC 不会。在虚拟机上试一试。
【讨论】:
CLOCK_PROCESS_CPUTIME_ID。快速测试:$ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)' --> 706724.117565279。这个数字与 Linux 上的系统正常运行时间相匹配,但标准说它是任意的。
CLOCK_MONOTONIC 在暂停/恢复时停止的 Linux 行为符合 POSIX。它应该是从过去某个固定点开始的时间,但是通过暂停/恢复停止时钟会破坏这一点。
POSIX 7 引号
POSIX 7 在http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html 处指定两者:
CLOCK_REALTIME:
此时钟代表系统测量实时的时钟。对于此时钟,由clock_gettime() 返回并由clock_settime() 指定的值表示自纪元以来的时间量(以秒和纳秒为单位)。
CLOCK_MONOTONIC(可选功能):
对于此时钟,clock_gettime() 返回的值表示自过去某个未指定时间点(例如,系统启动时间或纪元)以来的时间量(以秒和纳秒为单位)。该点在系统启动时间后不会改变。 CLOCK_MONOTONIC时钟的值不能通过clock_settime()设置。
clock_settime() 给出了一个重要提示:POSIX 系统可以随它任意改变CLOCK_REALITME,所以不要依赖它既不连续也不向前流动。 NTP 可以使用clock_settime() 实现,并且只能影响CLOCK_REALTIME。
Linux 内核实现似乎将引导时间作为CLOCK_MONOTONIC 的纪元:Starting point for CLOCK_MONOTONIC
【讨论】:
抱歉,没有声誉将此添加为评论。所以它作为一个补充答案。
根据您调用clock_gettime() 的频率,您应该记住只有一些的“时钟”是由Linux 在VDSO 中提供的(即不需要所有的系统调用)一个的开销——当 Linux 添加防御措施以防止类似 Spectre 的攻击时,这种情况只会变得更糟)。
虽然 clock_gettime(CLOCK_MONOTONIC,...)、clock_gettime(CLOCK_REALTIME,...) 和 gettimeofday() 总是会非常快(由 VDSO 加速),但对于例如CLOCK_MONOTONIC_RAW 或任何其他 POSIX 时钟。
这可能会随着内核版本和架构而改变。
虽然大多数程序不需要注意这一点,但 VDSO 加速的时钟可能会出现延迟峰值:如果您在内核使用时钟计数器更新共享内存区域时正确地击中它们,它必须等待内核完成。
这是“证明”(GitHub,让机器人远离 kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7
【讨论】:
CLOCK_REALTIME 和 MONOTONIC 之间有一个很大的区别。 CLOCK_REALTIME 可以根据 NTP 向前或向后跳跃。 默认情况下,NTP 允许时钟速率最多加快或减慢 0.05%,但 NTP 不能导致单调时钟向前或向后跳跃。
【讨论】: