在Linux中测量时间 – 时间vs时钟vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?
在时间函数中, time
getrusage
, clock_gettime
, gettimeofday
和timespec_get
,我想要清楚地知道它们是如何实现的以及它们的返回值是什么,以便知道在哪种情况下我必须使用它们。
首先,我们需要对返回挂钟值的函数进行分类,并与返回进程或线程值的函数进行比较。 gettimeofday
返回挂钟值, clock_gettime
根据传递给它的Clock
参数返回挂钟值或进程或线程值。 getrusage
和clock
返回过程值。
那么第二个问题就是关于这些function的实现以及它们的准确性。 这些function使用哪种硬件或软件机制。
似乎getrusage
只使用内核tick(通常为1ms长),因此不能比ms更准确。 这样对吗? 那么getimeofday
函数似乎使用了最精确的底层硬件。 因此,在最近的硬件上,其准确度通常是微秒(不能因为API而更多)。 关于clock
,手册页讲的是“逼近”,这是什么意思? 那么clock_gettime
,这个API在纳秒级,这是否意味着如果底层硬件允许的话它可以非常精确? 单调性呢?
还有其他的function吗?
问题是在C和C ++中有几个不同的时间函数,其中一些在实现之间有不同的行为。 还有很多的答案在四处stream动。 编译时钟函数列表及其属性将正确回答问题。 对于开始,我们来问一下我们正在寻找的相关属性。 看着你的post,我build议:
- 什么时间测量时钟? (真实的,用户的,系统的,还是希望不是挂钟?)
- 时钟的精度是多less? (s,ms,μs还是更快?)
- 时钟回绕了多less时间? 还是有一些机制可以避免这种情况?
- 时钟是单调的,还是会随着系统时间的变化而改变(通过NTP,时区,夏时制,用户等)?
- 以上各项如何变化?
- 具体的function是否过时,不标准等?
在开始列表之前,我想指出的是,挂钟时间几乎不是正确的使用时间,而是随着时区的变化,夏时制的变化或挂钟是否被NTP同步而改变。 如果您使用时间安排活动或基准testing,这些事情都不是很好。 这只是真正的名字所说,在墙上(或桌面)的时钟。
以下是我在Linux和OS X中发现的时钟:
-
time()
从OS返回挂钟时间,精确度以秒为单位。 -
clock()
似乎返回用户和系统时间的总和。 它出现在C89以后。 有一段时间应该是CPU周期的时间,但像POSIX这样的现代标准要求CLOCKS_PER_SEC为1000000,最大精度为1μs。 我的系统精度确实是1μs。 这个时钟一旦回到顶部(这通常发生在〜2 ^ 32个刻度之后,对于1MHz的时钟来说不是很长)。man clock
说,自glibc 2.18以来,它是在Linux中用clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)
的。 -
clock_gettime(CLOCK_MONOTONIC, ...)
提供纳秒分辨率,是单调的。 我相信“秒”和“纳秒”分别存储在32位计数器中。 因此,经过十几年的正常运行后,任何环绕都会发生。 这看起来像是一个非常好的时钟,但不幸的是它在OS X上还不可用CLOCK_MONOTONIC
7 将CLOCK_MONOTONIC
描述为可选的扩展 。 -
getrusage()
原来是我的情况的最佳select。 它分别报告用户和系统时间,不会环绕。 我的系统精度为1微秒,但我也在Linux系统上testing过(Red Hat 4.1.2-48和GCC 4.1.2),精度只有1毫秒。 -
gettimeofday()
以(名义上)μs的精度返回挂钟时间。 在我的系统上,这个时钟确实有μs精度,但是这并不能保证,因为“系统时钟的分辨率是依赖于硬件的” 。 POSIX.1-2008 说 。 “应用程序应该使用clock_gettime()
函数而不是过时的gettimeofday()
函数”,所以你应该远离它。 Linux x86并将其作为系统调用来实现 。 -
mach_absolute_time()
是OS X上非常高分辨率(ns)时序的一个选项。在我的系统中,这确实给出了ns分辨率。 原则上这个时钟环绕,但是它使用一个64位的无符号整数来存储ns,所以实际上这个环绕不应该是一个问题。 可移植性是值得怀疑的。 - 我写了一个基于这个片段 的混合函数 ,它在Linux上编译时使用clock_gettime,或者在OS X上编译时使用Mach计时器,以便在Linux和OS X上获得ns精度。
除非另有说明,所有以上都存在于Linux和OS X中。 上面的“我的系统”是一个运行OS X 10.8.3的Apple,MacPorts的GCC 4.7.2。
最后,这里是我发现除了以上链接之外还有帮助的参考文献列表:
- http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time
- 如何在Linux下测量C程序的ACTUAL执行时间?
- http://digitalsandwich.com/archives/27-benchmarking-misconceptions-microtime-vs-getrusage.html
- http://www.unix.com/hp-ux/38937-getrusage.html
更新 :对于OS X, clock_gettime
自10.12(Sierra)开始实施。 另外,基于POSIX和BSD的平台(如OS X)共享rusage.ru_utime
结构体字段。
C11 timespec_get
用法示例: https : //stackoverflow.com/a/36095407/895245
返回的最大可能精度是纳秒,但实际精度是实现定义的,可能更小。
它会返回挂墙时间,而不是CPU使用率。
glibc 2.21在sysdeps/posix/timespec_get.c
实现它,它直接转发到:
clock_gettime (CLOCK_REALTIME, ts) < 0)
clock_gettime
和CLOCK_REALTIME
是POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html,man man clock_gettime
表示如果在程序运行时更改一些系统时间设置,则此度量可能会有不连续性。
C ++ 11 chrono
既然我们在这,也让我们来介绍一下: http : //en.cppreference.com/w/cpp/chrono
GCC 5.3.0(C ++ stdlib在GCC源代码中):
-
high_resolution_clock
是system_clock
的别名 -
system_clock
转发到以下可用的第一个:-
clock_gettime(CLOCK_REALTIME, ...)
-
gettimeofday
-
time
-
-
steady_clock
转发到以下可用的第一个:-
clock_gettime(CLOCK_MONOTONIC, ...)
-
system_clock
-
问: 在std :: system_clock和std :: steady_clock之间的区别?
CLOCK_REALTIME
与CLOCK_MONOTONIC
: CLOCK_REALTIME和CLOCK_MONOTONIC之间的区别?