linux gettimeofday()的微秒时间是怎么得到的,它的精度是多少?

Posted

技术标签:

【中文标题】linux gettimeofday()的微秒时间是怎么得到的,它的精度是多少?【英文标题】:How is the microsecond time of linux gettimeofday() obtained and what is its accuracy? 【发布时间】:2012-10-25 04:57:55 【问题描述】:

挂钟时间通常由系统 RTC 提供。这主要只提供毫秒范围的时间,并且通常具有 10-20 毫秒的粒度。然而gettimeofday() 的分辨率/粒度通常是reported 在几微秒范围内。我假设微秒粒度必须来自不同的来源。

gettimeofday() 的微秒级分辨率/粒度是如何实现的?

当精确到毫秒的部分取自 RTC,而微秒取自不同的硬件时,就会出现两个源的定相问题。这两个来源必须是synchronized

这两个源之间的同步/定相是如何完成的?

编辑:根据我在 amdn 提供的链接中所读到的内容,特别是以下 Intel 链接,我想在这里添加一个问题:

gettimeofday() 是否提供微秒级别的分辨率/粒度?


编辑 2:总结 amdns answer 以及更多阅读结果:

Linux 仅在启动时使用实时时钟 (RTC) 与更高分辨率的计数器同步,例如时间戳计数器 (TSC)。启动后gettimeofday() 返回一个完全基于 TSC 值和此计数器频率的时间。 TSC frequency 的初始值通过将系统时间与外部时间源进行比较来校正/校准。调整由adjtimex() 函数完成/配置。内核运行锁相环以确保时间结果是单调一致的。

这样可以说gettimeofday() 具有微秒分辨率。考虑到更现代的时间戳计数器在 GHz 范围内运行,可获得的分辨率可能在纳秒范围内。因此,这个有意义的评论

/**
407  * do_gettimeofday - Returns the time of day in a timeval
408  * @tv:         pointer to the timeval to be set
409  *
410  * NOTE: Users should be converted to using getnstimeofday()
411  */

可以在Linux/kernel/time/timekeeping.c 中找到。这表明可能会有 是一个更高分辨率的功能,在以后的时间点可用。目前getnstimeofday() 仅在内核空间中可用。

但是,查看所有涉及的代码以使其正确无误,显示了很多关于不确定性的问题。有可能获得微秒级的分辨率。函数gettimeofday() 甚至可以显示微秒级别的粒度。 但是:对其准确性存在严重质疑,因为无法准确校正 TSC 频率的drift。此外,在 Linux 中处理此问题的代码的复杂性暗示着要正确处理它实际上太难了。这特别是但不仅仅是由于 Linux 应该在其上运行的大量硬件平台造成的。

结果: gettimeofday() 返回以微秒为粒度的单调时间,但它提供的时间几乎从不与 one microsecond 与任何其他时间源成相位。

【问题讨论】:

归根结底,粒度取决于所涉及的硬件。我假设算法使用 100 毫秒。这是由于考虑了上下文切换等。 【参考方案1】:

Linux 启动时,它使用硬件时钟初始化软件时钟。请参阅Clock HOWTO 中的章节How Linux Keeps Track of Time。

【讨论】:

Linux 如何跟踪时间:"...“系统时钟”(有时称为“内核时钟”或“软件时钟”),它是基于定时器的软件计数器中断。” 我不知道如何以这种方式获得微秒粒度,因为我确实怀疑 定时器中断 以如此高的频率运行。 您可以只查询定时器的当前计数器值以获得比定时器频率更精细的分辨率。 CPU的计时远比RTC的计时准确。 CPU 可以简单地计算时钟周期的周期。缺点是电脑关机时不能使用CPU的定时器。 我知道高分辨率计数器。但是 gettimeofday() 似乎将系统时间与高分辨率计数器联系起来,因为它同时提供:一次调用即可获得挂钟 微秒。那么gettimeofday()的幕后是什么?这就是问题的全部内容。【参考方案2】:

gettimeofday() 的微秒级分辨率/粒度是如何实现的?

Linux 在许多不同的硬件平台上运行,因此具体情况有所不同。在现代 x86 平台上,Linux 使用Time Stamp Counter,也称为TSC,它由多个运行在 133.33 MHz 的晶体振荡器驱动。晶体振荡器为处理器提供参考时钟,处理器将其乘以某个倍数 - 例如,在 2.93 GHz 处理器上,倍数是 22。TSC 在历史上是一个不可靠的时间来源,因为实现会停止计数器处理器进入睡眠状态,或者因为倍数不是恒定的,因为处理器移动乘数以更改performance states 或在变热时减速。现代 x86 处理器提供了一个TSC,它是恒定的、不变的和不间断的。在这些处理器上,TSC 是一个出色的高分辨率时钟,Linux 内核在启动时确定初始近似频率。 TSC 为 gettimeofday() 系统调用提供微秒分辨率,为 clock_gettime() 系统调用提供纳秒分辨率。

这种同步是如何完成的?

你的第一个问题是关于Linux时钟如何提供高分辨率的,第二个问题是关于同步的,这是precision and accuracy的区别。大多数系统都有一个由电池备份的时钟,以在系统断电时保持一天中的时间。正如您可能期望的那样,这个时钟没有很高的准确度或精度,但它会在系统启动时“在球场上”获得一天中的时间。为了获得准确性,大多数系统使用可选组件从网络上的外部源获取时间。两个常见的是

    Network Time Protocol Precision Time Protocol

这些协议在网络上定义一个主时钟(或由原子钟提供的时钟层),然后测量网络延迟以估计与主时钟的偏移。一旦确定了与主设备的偏移量,系统时钟为disciplined 以保持准确。这可以通过

    步进时钟(相对较大、突然且不频繁的时间调整),或 Slewing 时钟(定义为在给定时间段内通过缓慢增加或减少频率来调整时钟频率的程度)

内核提供adjtimex system call 以允许时钟约束。有关现代 Intel 多核处理器如何在内核之间保持 TSC 同步的详细信息,请参阅CPU TSC fetch operation especially in multicore-multi-processor environment。

时钟调整的相关内核源文件为kernel/time.c和kernel/time/timekeeping.c。

【讨论】:

Linux 内核在初始化时决定频率, 所以它假设是一个常数。但gettimeofday() 也使用 RTC 与之同步。因此,似乎有两个来源,RTC 和 TSC。我的问题是关于这两个来源的同步。特别是 TSC 频率在这里似乎很重要,因为生成硬件肯定有一些容差,仅 10 ppm 的偏差将导致 10 微秒/秒的误差。因此,RTC 给出的一秒可能对应于 TSC 给出的 1.000010 秒。 我想得到这个模棱两可的答案,因为 TSC 频率被 Linux 视为会偏离实际频率的任意常数。 TSC 频率不假定是恒定的,它会定期调整,这就是 adjtimex 系统调用的用途。用户空间程序/守护进程(如 NTP 和 PTP)使用 adjtimex 告诉 Linux 如何slew 随时间变化的频率。 换句话说:周期性程序校准TSC频率,周期由RTC(系统时钟)给出?因此,将 TSC 计数器的变化与 RTC(系统时钟)的经过时间进行比较。因此,生成的 TSC 频率被校准为精确到 100 万微秒/秒?而这一切都在幕后不断进行? 我已经在我的问题中总结了。

以上是关于linux gettimeofday()的微秒时间是怎么得到的,它的精度是多少?的主要内容,如果未能解决你的问题,请参考以下文章

gettimeofday

想精度高,可以考虑用c语言中的函数gettimeofday

如何在windows开发环境下得到精确到微秒的系统时间?

为啥微秒时间戳使用(私有)gettimeoftheday()重复,即纪元

linux时间和定时器zz

java中的当前时间(以微秒为单位)