在 C 中获取以微秒为单位的时间戳?
如何在 C 中获取微秒时间戳?
我正在尝试这样做:
struct timeval tv;
gettimeofday(&tv,NULL);
return tv.tv_usec;
但这会返回一些无意义的值,如果我得到两个时间戳,第二个时间戳可以比第一个时间戳更小或更大(第二个应该始终更大)。是否可以将 gettimeofday 返回的魔法整数转换为实际可以使用的普通数字?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您还需要添加秒数:
请注意,这只会持续大约 232/106 =~ 4295 秒,或者大约 71 分钟(在典型的 32 位系统)。
You need to add in the seconds, too:
Note that this will only last for about 232/106 =~ 4295 seconds, or roughly 71 minutes though (on a typical 32-bit system).
您有两种选择来获取微秒时间戳。第一个(也是最好的)选择是直接使用
timeval
类型:第二个选择(对我来说不太理想)是从
timeval
构建 uint64_t:You have two choices for getting a microsecond timestamp. The first (and best) choice, is to use the
timeval
type directly:The second, and for me less desirable, choice is to build a uint64_t out of a
timeval
:以下是与此问题的标题相关的通用答案:
How to get a simple timestamp in C
millis()
,micros()
计算,nanos()
计算纳秒 (ns)快速总结:如果您很着急并且使用 Linux 或 POSIX 系统,请跳转直接进入标题为的部分下面的“
millis()
、micros()
和nanos()
”,只需使用这些函数即可。如果您在 Linux 或 POSIX 系统上不使用 C11,则需要将这些函数中的clock_gettime()
替换为timespec_get()
>.C 中的 2 个主要时间戳函数:
C11:
timespec_get()
是 C11 或更高版本标准的一部分,但不允许选择时钟类型使用。它也适用于 C++17。请参阅此处的std::timespec_get()
文档一个>。但是,对于 C++11 及更高版本,我更喜欢使用不同的方法,我可以指定时钟的分辨率,正如我在此处的答案中演示的那样:获取准确的执行时间在 C++ 中(微秒)。C11
timespec_get()
解决方案比 C++ 解决方案有更多限制,因为您无法指定时钟分辨率或单调性(“单调”时钟定义为仅计数的时钟)向前,并且永远不能向后移动或跳跃——例如:用于时间校正)。测量时间差时,需要单调时钟以确保您永远不会将时钟校正跳跃算作“测量”时间的一部分。由于我们无法指定要使用的时钟,
timespec_get()
返回的时间戳值的分辨率可能取决于您的硬件架构, 操作系统和编译器。通过快速连续进行 1000 次左右的测量,然后找到任意两次后续测量之间的最小差异,可以获得该函数分辨率的近似值。您时钟的实际分辨率保证等于或小于最小差异。我在 get_estimated_resolution() 函数中演示了这一点“noreferrer">timinglib.c 用于 Linux 的时序库。
Linux 和 POSIX: 比 C 语言中的
timespec_get()
更好是 Linux 和 POSIX 函数clock_gettime()
函数,在 Linux 上的 C++ 中也能正常工作或 POSIX 系统。clock_gettime()
确实允许您选择所需的时钟。您可以使用clock_getres()
读取指定的时钟分辨率,尽管这也不能为您提供硬件的真实时钟分辨率。相反,它为您提供struct timespec
的tv_nsec
成员的单位。使用上面和我的 timinglib.c/.h 文件以获得分辨率的估计。因此,如果您在 Linux 或 POSIX 系统上使用 C,我强烈建议您使用
clock_gettime()
而不是timespec_get()
.C11 的
timespec_get()
(好的)和 Linux/POSIX 的clock_gettime()
(更好):以下是如何使用这两个函数:
timespec_get()
clock_gettime()
< /a> -- 尽可能使用这个!CLOCK_MONOTONIC_RAW
时钟,它最适合获取用于为系统上的事件计时的时间戳。CLOCK_REALTIME
、CLOCK_MONOTONIC
、CLOCK_MONOTONIC_RAW
等:https://man7.org/linux/man-pages/man3/clock_gettime.3.htmlCLOCK_REALTIME
。不过,请不要混淆! “实时”并不意味着它是用于“实时”操作系统或精确计时的好时钟。相反,它意味着它是一个时钟,如果时钟漂移,它将定期调整到“实时”或实际的“世界时间”。再次强调,请勿将此时钟用于精确计时,因为系统可以随时向前或向后调整它,而不受您的控制。millis()
、micros()
和nanos()
:无论如何,这是我的
millis()
,我在 C 中使用micros()
和nanos()
函数来进行简单的时间戳和代码速度分析。我正在使用下面的 Linux/POSIX
clock_gettime()
函数。如果您在没有可用clock_gettime()
的系统上使用 C11 或更高版本,只需替换clock_gettime(CLOCK_MONOTONIC_RAW, &ts)< 的所有用法即可/code> 下面用
timespec_get(&ts, TIME_UTC)
代替。从我的 eRCaGuy_hello_world 存储库获取最新版本的代码:
时间戳分辨率:
在带有 gcc 编译器的 x86-64 Linux Ubuntu 18.04 系统上,
clock_getres()
返回的分辨率为1 纳秒。对于
clock_gettime()
和timespec_get()
,我还进行了实证测试,我尽可能快地获取 1000 个时间戳(请参阅get_estimated_resolution()我的 功能rel="noreferrer">timinglib.c 计时库),并查看时间戳样本之间的最小间隙是多少。当使用
timespec_get(&ts, TIME_UTC)
和clock_gettime(CLOCK_MONOTONIC, &ts)< 时,这揭示了我的系统上 ~14~26 ns 的范围/code> 和 ~75~130 ns 对于
clock_gettime(CLOCK_MONOTONIC_RAW, &ts)
。这可以被认为是这些函数的粗略“实际解决方案”。请参阅timinglib_get_resolution.c
,并查看我的get_estimated_resolution()
和get_specified_resolution()
函数的定义(其中由该测试代码使用)在timinglib.c
。这些结果是特定于硬件的,您的硬件上的结果可能会有所不同。
参考:
usleep()
和nanosleep()
的回答 - 它提醒了我需要执行#define _POSIX_C_SOURCE 199309L
才能从
引入clock_gettime()
POSIX 函数!<块引用>
_POSIX_C_SOURCE >= 199309L
CLOCK_REALTIME
、CLOCK_MONOTONIC
、CLOCK_MONOTONIC_RAW
等。另请参阅:
clock_gettime()
:https:// pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlclock_gettime()
: https://linux.die.net/man/3/clock_gettimetimespec_get()
(正如我上面所做的那样),而不是 POSIXclock_gettime()
。 https://en.cppreference.com/w/c/chrono/clock说:<块引用>
在 C11 中使用 timespec_get
clock_gettime()
可以让您为您想要的时钟类型选择所需的时钟 ID!另请参阅此处: ***** https:// /people.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html待办事项:
timespec_getres()
直到 C23 才支持,将我的示例更新为其中包括在 Linux 上使用 POSIXclock_gettime()
和clock_getres()
函数的函数。我想确切地知道在给定系统上我可以期望的时钟分辨率有多好。 是 ms-resolution、us-resolution、ns-resolution 还是其他什么?有关参考,请参阅:clock_getres()
返回1 ns,但实际分辨率约为14~27 ns,根据我的get_estimated_resolution()
函数在这里:https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/timinglib.c。在这里查看结果:SCHED_RR
软实时循环调度程序,以获得最佳且最一致的时序。请参阅我关于clock_nanosleep()
的回答:如何配置 Linux SCHED_RR 软实时循环调度程序这样,clock_nanosleep() 的分辨率可以从约 55 us 提高到约 4 us。Here is a generic answer pertaining to the title of this question:
How to get a simple timestamp in C
millis()
,micros()
, andnanos()
Quick summary: if you're in a hurry and using a Linux or POSIX system, jump straight down to the section titled "
millis()
,micros()
, andnanos()
", below, and just use those functions. If you're using C11 not on a Linux or POSIX system, you'll need to replaceclock_gettime()
in those functions withtimespec_get()
.2 main timestamp functions in C:
C11:
timespec_get()
is part of the C11 or later standard, but doesn't allow choosing the type of clock to use. It also works in C++17. See documentation forstd::timespec_get()
here. However, for C++11 and later, I prefer to use a different approach where I can specify the resolution and type of the clock instead, as I demonstrate in my answer here: Getting an accurate execution time in C++ (micro seconds).The C11
timespec_get()
solution is a bit more limited than the C++ solution in that you cannot specify the clock resolution nor the monotonicity (a "monotonic" clock is defined as a clock that only counts forwards and can never go or jump backwards--ex: for time corrections). When measuring time differences, monotonic clocks are desired to ensure you never count a clock correction jump as part of your "measured" time.The resolution of the timestamp values returned by
timespec_get()
, therefore, since we can't specify the clock to use, may be dependent on your hardware architecture, operating system, and compiler. An approximation of the resolution of this function can be obtained by rapidly taking 1000 or so measurements in quick-succession, then finding the smallest difference between any two subsequent measurements. Your clock's actual resolution is guaranteed to be equal to or smaller than that smallest difference.I demonstrate this in the
get_estimated_resolution()
function of my timinglib.c timing library intended for Linux.Linux and POSIX: Even better than
timespec_get()
in C is the Linux and POSIX functionclock_gettime()
function, which also works fine in C++ on Linux or POSIX systems.clock_gettime()
does allow you to choose the desired clock. You can read the specified clock resolution withclock_getres()
, although that doesn't give you your hardware's true clock resolution either. Rather, it gives you the units of thetv_nsec
member of thestruct timespec
. Use myget_estimated_resolution()
function described just above and in my timinglib.c/.h files to obtain an estimate of the resolution.So, if you are using C on a Linux or POSIX system, I highly recommend you use
clock_gettime()
overtimespec_get()
.C11's
timespec_get()
(ok) and Linux/POSIX'sclock_gettime()
(better):Here is how to use both functions:
timespec_get()
clock_gettime()
-- USE THIS ONE WHENEVER POSSIBLE!CLOCK_MONOTONIC_RAW
clock, which is best for obtaining timestamps used to time things on your system.CLOCK_REALTIME
,CLOCK_MONOTONIC
,CLOCK_MONOTONIC_RAW
, etc: https://man7.org/linux/man-pages/man3/clock_gettime.3.htmlCLOCK_REALTIME
. Do NOT be confused, however! "Realtime" does NOT mean that it is a good clock to use for "realtime" operating systems, or precise timing. Rather, it means it is a clock which will be adjusted to the "real time", or actual "world time", periodically, if the clock drifts. Again, do NOT use this clock for precise timing usages, as it can be adjusted forwards or backwards at any time by the system, outside of your control.millis()
,micros()
, andnanos()
:Anyway, here are my
millis()
,micros()
, andnanos()
functions I use in C for simple timestamps and code speed profiling.I am using the Linux/POSIX
clock_gettime()
function below. If you are using C11 or later on a system which does not haveclock_gettime()
available, simply replace all usages ofclock_gettime(CLOCK_MONOTONIC_RAW, &ts)
below withtimespec_get(&ts, TIME_UTC)
instead.Get the latest version of my code here from my eRCaGuy_hello_world repo here:
Timestamp Resolution:
On my x86-64 Linux Ubuntu 18.04 system with the gcc compiler,
clock_getres()
returns a resolution of 1 ns.For both
clock_gettime()
andtimespec_get()
, I have also done empirical testing where I take 1000 timestamps rapidly, as fast as possible (see theget_estimated_resolution()
function of my timinglib.c timing library), and look to see what the minimum gap is between timestamp samples. This reveals a range of ~14~26 ns on my system when usingtimespec_get(&ts, TIME_UTC)
andclock_gettime(CLOCK_MONOTONIC, &ts)
, and ~75~130 ns forclock_gettime(CLOCK_MONOTONIC_RAW, &ts)
. This can be considered the rough "practical resolution" of these functions. See that test code intiminglib_get_resolution.c
, and see the definition for myget_estimated_resolution()
andget_specified_resolution()
functions (which are used by that test code) intiminglib.c
.These results are hardware-specific, and your results on your hardware may vary.
References:
usleep()
andnanosleep()
- it reminded me I needed to do#define _POSIX_C_SOURCE 199309L
in order to bring in theclock_gettime()
POSIX function from<time.h>
!CLOCK_REALTIME
,CLOCK_MONOTONIC
,CLOCK_MONOTONIC_RAW
, etc.See also:
clock_gettime()
: https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlclock_gettime()
on Linux: https://linux.die.net/man/3/clock_gettimetimespec_get()
, as I have done above, instead of POSIXclock_gettime()
. https://en.cppreference.com/w/c/chrono/clock says:clock_gettime()
instead allows you to choose a desired clock ID for the type of clock you want! See also here: ***** https://people.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.htmlTodo:
timespec_getres()
isn't supported until C23, update my examples to include one which uses the POSIXclock_gettime()
andclock_getres()
functions on Linux. I'd like to know precisely how good the clock resolution is that I can expect on a given system. Is it ms-resolution, us-resolution, ns-resolution, something else? For reference, see:clock_getres()
returns 1 ns, but the actual resolution is about 14~27 ns, according to myget_estimated_resolution()
function here: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/timinglib.c. See the results here:SCHED_RR
soft real-time round-robin scheduler for the best and most-consistent timing possible. See my answer here regardingclock_nanosleep()
: How to configure the Linux SCHED_RR soft real-time round-robin scheduler so that clock_nanosleep() can have improved resolution of ~4 us down from ~ 55 us.struct timeval 包含两个部分,秒和微秒。微秒精度的时间戳表示为自 tv_sec 字段中存储的纪元以来的秒数和 tv_usec 中的小数微秒。因此,您不能仅仅忽略 tv_sec 并期望得到合理的结果。
如果您使用Linux或*BSD,您可以使用timersub()来减去两个struct timeval值,这可能是您想要的。
struct timeval contains two components, the second and the microsecond. A timestamp with microsecond precision is represented as seconds since the epoch stored in the tv_sec field and the fractional microseconds in tv_usec. Thus you cannot just ignore tv_sec and expect sensible results.
If you use Linux or *BSD, you can use timersub() to subtract two struct timeval values, which might be what you want.
timespec_get
from C11返回精度高达纳秒的值,四舍五入到实现的分辨率。
请参阅我的其他答案中的更多详细信息:如何使用 ANSI C 测量以毫秒为单位的时间?
timespec_get
from C11Returns with precision of up to nanoseconds, rounded to the resolution of the implementation.
See more details in my other answer here: How to measure time in milliseconds using ANSI C?
是什么让你这么想?价值大概还可以。这与秒和分钟的情况相同 - 当您以分钟和秒来测量时间时,当秒数达到 60 时,秒数就会滚到零。
要将返回值转换为“线性”数字,您可以乘以秒数并加上微秒。但如果我计算正确的话,一年大约是 1e6*60*60*24*360μsec,这意味着您需要超过 32 位来存储结果:
这可能是将原始返回值拆分为的原因之一两块。
What makes you think that? The value is probably OK. It’s the same situation as with seconds and minutes – when you measure time in minutes and seconds, the number of seconds rolls over to zero when it gets to sixty.
To convert the returned value into a “linear” number you could multiply the number of seconds and add the microseconds. But if I count correctly, one year is about 1e6*60*60*24*360 μsec and that means you’ll need more than 32 bits to store the result:
That’s probably one of the reasons to split the original returned value into two pieces.
使用unsigned long long(即64位单元)来表示系统时间:
use an unsigned long long (i.e. a 64 bit unit) to represent the system time:
迟到总比不到好!这个小程序可以用作获取时间戳(以微秒为单位)并计算进程时间(以微秒为单位)的最快方法:
您可以用函数/进程替换 getchar() 。最后,您可以将其存储在有符号长整型中,而不是打印差异。该程序在 Windows 10 中运行良好。
Better late than never! This little programme can be used as the quickest way to get time stamp in microseconds and calculate the time of a process in microseconds:
You can replace getchar() with a function/process. Finally, instead of printing the difference you can store it in a signed long. The programme works fine in Windows 10.
首先我们需要知道微秒的范围,即000_000到999_999(1000000微秒等于1秒)。 tv.tv_usec 将返回从 0 到 999999 的值,而不是 000000 到 999999,因此当将其与秒一起使用时,我们可能会得到 2.1 秒而不是 2.000001 秒,因为当仅谈论 tv_usec 000001 时本质上是 1。
如果你插入
等等就更好了...
First we need to know on the range of microseconds i.e. 000_000 to 999_999 (1000000 microseconds is equal to 1second). tv.tv_usec will return value from 0 to 999999 not 000000 to 999999 so when using it with seconds we might get 2.1seconds instead of 2.000001 seconds because when only talking about tv_usec 000001 is essentially 1.
Its better if you insert
and so on...