Linux的clock_gettime(CLOCK_MONOTONIC)函数表现出奇怪的非单调行为

29

各位,我的应用程序中使用clock_gettime(CLOCK_MONOTONIC)来测量帧之间的时间差(游戏开发中的典型方法),但有时会出现clock_gettime(..)的奇怪行为——返回值偶尔不是单调递增的(即上一个时间大于当前时间)。

目前,如果发生这种矛盾,我只需跳过当前帧并开始处理下一帧。

问题是这怎么可能?这是Linux POSIX实现clock_gettime的bug吗?我正在使用Ubuntu Server Edition 10.04(内核2.6.32-24,x86_64),gcc-4.4.3。


你有没有在虚拟环境中运行它? - caf
没有,没有涉及虚拟化。 - pachanga
5个回答

24

man clock_gettime 说:

CLOCK_MONOTONIC_RAW (自 Linux 2.6.28 版本起;仅限 Linux)

类似于 CLOCK_MONOTONIC,但提供对硬件时间的访问,该时间不受 NTP 调整的影响。

由于 CLOCK_MONOTONIC_RAW 不受 NTP 调整的影响,我想 CLOCK_MONOTONIC 可能会受到影响。

我们在 Redhat Enterprise 5.0 上使用 2.6.18 内核和某些特定 Itanium 处理器时遇到了类似的问题。但我们无法在同一操作系统上的其他处理器上重现此问题。它在 RHEL 5.3 中修复了,其中包括稍微更新的内核和一些 Redhat 补丁。


1
谢谢你的提示。这是给我的又一课 - 永远不要绝对信任即使是最可靠的库 :) - pachanga
6
我曾经从事内核时钟功能的工作。按照设计,MONOTONIC时钟不应该倒退,这几乎是默认的。 - Edward Falk
14
实际上,MONOTONIC被实现为相对于REALTIME的偏移量。每当实时时钟被调整或系统休眠时,都会调整该偏移量。在错误的情况下,可能会错误地计算偏移量,导致MONOTONIC时钟跳跃,甚至是向后跳跃。 - Edward Falk
1
OP没有提到错误有多大,但这是我的经验:大多数硬件内置的实时时钟只提供最接近秒的时间,而Linux在内部保持最接近微秒或纳秒的时间。当Linux进入睡眠和唤醒时,会尝试解决这些问题,但逻辑相当复杂,我不理解它。加上由NTP调整、用户时间调整和其他未知因素引起的REALTIME调整,你就会得到一个混乱的配方。底线是,我并不真正惊讶MONTONIC有时会倒退。 - Edward Falk
12
CLOCK_MONOTONIC不应向后(或向前)跳动;如果出现这种情况,则表示存在错误。它受NTP守护程序的微妙调整影响(看起来是每500万分之一),而CLOCK_MONOTONIC_RAW则没有。我理解“原始”单调时钟可能不是100%准确的,因此NTP守护程序可以稍微加快或减慢时间流逝,使其与实际时间相匹配。如果您想每秒执行N次操作,则非原始时钟可能更准确。 - fadden
显示剩余4条评论

21

看起来是一个实例

commit 0696b711e4be45fa104c12329f617beb29c03f78
Author: Lin Ming <ming.m.lin@intel.com>
Date:   Tue Nov 17 13:49:50 2009 +0800

timekeeping: Fix clock_gettime vsyscall time warp

Since commit 0a544198 "timekeeping: Move NTP adjusted clock
multiplier to struct timekeeper" the clock multiplier of vsyscall is updated with
the unmodified clock multiplier of the clock source and not with the
NTP adjusted multiplier of the timekeeper.

This causes user space observerable time warps:
new CLOCK-warp maximum: 120 nsecs,  00000025c337c537 -> 00000025c337c4bf
请查看此处的补丁。这个补丁已经包含在2.6.32.19版本中,但可能还未被Debian团队反向移植。你应该去核实它。

6
尝试使用。

4

6
Bug跟踪工具很好用,提交bug也是如此(每个人都应该这样做),但它们不受欢迎,因为程序员想要立即解决问题。通常,在你完成大部分项目编码之后,上游bug才会得到修复,并且你必须支持那些长时间没有升级上游库的人。 :( - Matt Joiner

0

这是一个Linux的bug。在单调时钟中进行任何调整都无法使其倒退。您正在使用非常旧的内核和非常旧的发行版。

编辑:您确定需要跳过该帧吗?如果再次调用clock_gettime,会发生什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接