// This line **must** come **before** including <time.h> in order to
// bring in the POSIX functions such as `clock_gettime() from <time.h>`!
#define _POSIX_C_SOURCE 199309L
#include <errno.h> // `errno`
#include <stdint.h> // `UINT64_MAX`
#include <stdio.h> // `printf()`
#include <string.h> // `strerror(errno)`
#include <time.h> // `clock_gettime()` and `timespec_get()`
/// Convert seconds to nanoseconds
#define SEC_TO_NS(sec) ((sec)*1000000000)
uint64_t nanoseconds;
struct timespec ts;
int return_code = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
if (return_code == -1)
{
printf("Failed to obtain timestamp. errno = %i: %s\n", errno,
strerror(errno));
nanoseconds = UINT64_MAX; // use this to indicate error
}
else
{
// `ts` now contains your timestamp in seconds and nanoseconds! To
// convert the whole struct to nanoseconds, do this:
nanoseconds = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;
}
// This line **must** come **before** including <time.h> in order to
// bring in the POSIX functions such as `clock_gettime() from <time.h>`!
#define _POSIX_C_SOURCE 199309L
#include <time.h>
/// Convert seconds to milliseconds
#define SEC_TO_MS(sec) ((sec)*1000)
/// Convert seconds to microseconds
#define SEC_TO_US(sec) ((sec)*1000000)
/// Convert seconds to nanoseconds
#define SEC_TO_NS(sec) ((sec)*1000000000)
/// Convert nanoseconds to seconds
#define NS_TO_SEC(ns) ((ns)/1000000000)
/// Convert nanoseconds to milliseconds
#define NS_TO_MS(ns) ((ns)/1000000)
/// Convert nanoseconds to microseconds
#define NS_TO_US(ns) ((ns)/1000)
/// Get a time stamp in milliseconds.
uint64_t millis()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
uint64_t ms = SEC_TO_MS((uint64_t)ts.tv_sec) + NS_TO_MS((uint64_t)ts.tv_nsec);
return ms;
}
/// Get a time stamp in microseconds.
uint64_t micros()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
uint64_t us = SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec);
return us;
}
/// Get a time stamp in nanoseconds.
uint64_t nanos()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
uint64_t ns = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;
return ns;
}
// NB: for all 3 timestamp functions above: gcc defines the type of the internal
// `tv_sec` seconds value inside the `struct timespec`, which is used
// internally in these functions, as a signed `long int`. For architectures
// where `long int` is 64 bits, that means it will have undefined
// (signed) overflow in 2^64 sec = 5.8455 x 10^11 years. For architectures
// where this type is 32 bits, it will occur in 2^32 sec = 136 years. If the
// implementation-defined epoch for the timespec is 1970, then your program
// could have undefined behavior signed time rollover in as little as
// 136 years - (year 2021 - year 1970) = 136 - 51 = 85 years. If the epoch
// was 1900 then it could be as short as 136 - (2021 - 1900) = 136 - 121 =
// 15 years. Hopefully your program won't need to run that long. :). To see,
// by inspection, what your system's epoch is, simply print out a timestamp and
// calculate how far back a timestamp of 0 would have occurred. Ex: convert
// the timestamp to years and subtract that number of years from the present
// year.
时间戳分辨率:
在我使用gcc编译器的x86 - 64 Linux Ubuntu 18.04系统上,clock_getres()返回1 ns的分辨率。
#include <sys/time.h>
#include <stdio.h>
#include <time.h>
struct timeval GetTimeStamp()
{
struct timeval tv;
gettimeofday(&tv,NULL);
return tv;
}
int main()
{
struct timeval tv= GetTimeStamp(); // Calculate time
signed long time_in_micros = 1000000 * tv.tv_sec + tv.tv_usec; // Store time in microseconds
getchar(); // Replace this line with the process that you need to time
printf("Elapsed time: %ld microsecons\n", (1000000 * GetTimeStamp().tv_sec + GetTimeStamp().tv_usec) - time_in_micros);
}
9条答案
按热度按时间w80xi6nr1#
您还需要添加秒数:
请注意,这只会持续大约232/106 =~ 4295秒,或者大约71分钟(在典型的32位系统上)。
rqqzpn5f2#
获取微秒时间戳有两种选择,第一种(也是最好的)选择是直接使用
timeval
类型:第二种选择(对我来说不太理想)是从
timeval
构建uint64_t:oewdyzsn3#
在C中获得以微秒为单位的时间戳?
以下是与此问题的 * 标题 * 相关的一般答案:
如何在C中获取简单的时间戳
1.对于函数
millis()
以毫秒(ms)为单位,1.微秒(us),
micros()
,以及1.纳秒(ns),
nanos()
millis()
,micros()
,和nanos()
"部分,然后使用这些函数。如果你在Linux或POSIX系统上使用C11而不是,你需要用timespec_get()
替换这些函数中的clock_gettime()
。*C语言中的2个主要时间戳函数:
1.* * C11:****
timespec_get()
是 * C11 * 或更高版本标准的一部分,但不允许选择要使用的时钟类型。它也适用于C17。请参见documentation forstd::timespec_get()
here。但是,对于C11及更高版本,我更喜欢使用一种不同的方法,我可以 * 指定分辨率 * 和时钟类型,如我在此处的答案中所演示的:在C中获得精确的执行时间(微秒)。C11
timespec_get()
解决方案比C解决方案的局限性稍大一些,因为您不能指定时钟分辨率或单调性("单调"时钟定义为只能向前计数并且 * 永远 * 不能向后运行或跳转的时钟--例如:当测量时间差时,单调时钟是理想的,以确保您永远不会将时钟校正跳变计数为您"测量"时间的一部分。因此,由于我们无法指定要使用的时钟,
timespec_get()
返回的时间戳值的分辨率可能取决于您的 * 硬件架构 、 操作系统 * 和 * 编译器 。该函数分辨率的 * 近似值 * 可以通过快速连续地进行1000次左右的测量来获得。然后找到任意两个后续测量值之间的最小差值。您的时钟的实际 * 分辨率 * 保证 * 等于或小于 * 该最小差值。我在我的timinglib.c定时库的
get_estimated_resolution()
函数中演示了这一点。1. * Linux和POSIX:****比C中的
timespec_get()
更好的是Linux and POSIX functionclock_gettime()
函数,它在Linux或POSIX系统上的C++中也能很好地工作。clock_gettime()
**允许您选择所需的时钟。您可以使用clock_getres()
读取指定的时钟分辨率,尽管这也不会给您硬件的真实时钟分辨率。相反,它给您struct timespec
的tv_nsec
成员的单位。使用我上面描述的get_estimated_resolution()
函数和我的timinglib.c/. h文件来获得分辨率的估计值。clock_gettime()
而不是timespec_get()
。**C11的
timespec_get()
(不错)和Linux/POSIX的clock_gettime()
(更好):以下是如何使用这两个函数:
1.* * C11的
timespec_get()
**1.在C中工作,但不允许您选择要使用的时钟。
1.* * 完整示例,带错误检查:**
1.* * Linux/POSIX的
clock_gettime()
**--* 尽可能使用此版本! *1.在Linux或POSIX系统上用C语言工作,并允许您选择要使用的时钟!
1.我选择了
CLOCK_MONOTONIC_RAW
时钟,它最适合于获取系统上用于计时的时间戳。1.请参阅此处所有时钟类型的定义,例如
CLOCK_REALTIME
、CLOCK_MONOTONIC
、CLOCK_MONOTONIC_RAW
等:https://man7.org/linux/man-pages/man3/clock_gettime.3.html1.另一个流行的时钟是
CLOCK_REALTIME
。但是,不要混淆!"实时"并不意味着它是一个用于"实时"操作系统或精确计时的好时钟。相反,它意味着如果时钟漂移,它是一个将定期调整到"实时"或实际"世界时间"的时钟。同样,不要将此时钟用于精确计时用途,因为它可以在任何时候由系统向前或向后调整,不受您的控制。1.* * 完整示例,带错误检查:**
millis()
、micros()
和nanos()
:无论如何,下面是我在C语言中使用的
millis()
、micros()
和nanos()
函数,用于简单的时间戳和代码速度分析。我正在使用下面的Linux/POSIX
clock_gettime()
函数。如果您在 * 没有 *clock_gettime()
可用的系统上使用C11或更高版本,只需将下面所有clock_gettime(CLOCK_MONOTONIC_RAW, &ts)
的用法替换为timespec_get(&ts, TIME_UTC)
即可。从我的eRCaGuy_hello_world repo获取我的代码的最新版本:
时间戳分辨率:
在我使用gcc编译器的x86 - 64 Linux Ubuntu 18.04系统上,
clock_getres()
返回1 ns的分辨率。对于
clock_gettime()
和timespec_get()
,我还进行了经验测试,其中我尽可能快地获取了1000个时间戳(参见我的timinglib.c定时库的get_estimated_resolution()
函数),并查看时间戳样本之间的最小间隔。这表明范围为**~14~26 ns在我的系统上使用timespec_get(&ts, TIME_UTC)
和clock_gettime(CLOCK_MONOTONIC, &ts)
时,~75~130 ns**(对于clock_gettime(CLOCK_MONOTONIC_RAW, &ts)
)。这可视为这些函数的粗略"实际分辨率"。请参见timinglib_get_resolution.c
中的测试代码,并参见timinglib.c
中我的get_estimated_resolution()
和get_specified_resolution()
函数(该测试代码使用的函数)的定义。参考文献:
1.我在上面链接到的www.example.com文档源。 cppreference.com documentation sources I link to above.
1.[我的答案] my answer about
usleep()
andnanosleep()
-它提醒我需要做#define _POSIX_C_SOURCE 199309L
才能从<time.h>
引入clock_gettime()
POSIX函数!1.提及以下要求:
_POSIX_C_SOURCE >= 199309L
1.请参阅这里所有时钟类型的定义,例如
CLOCK_REALTIME
、CLOCK_MONOTONIC
、CLOCK_MONOTONIC_RAW
等。另请参见:
1.我的答案比较简短,只适用于ANSI/ISO C11或更高版本:How to measure time in milliseconds using ANSI C?
1.我的3组时间戳函数(相互交叉链接):
1.对于C时间戳,请参见我的答案:Get a timestamp in C in microseconds?
1.对于C++高分辨率时间戳,请参见我的答案:Here is how to get simple C-like millisecond, microsecond, and nanosecond timestamps in C++
1.对于Python高分辨率时间戳,请参见我的答案:How can I get millisecond and microsecond-resolution timestamps in Python?
clock_gettime()
:https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlclock_gettime()
:https://linux.die.net/man/3/clock_gettime1.注意:对于C11和更高版本,您 * 可以 * 使用
timespec_get()
,就像我在上面所做的那样,而不是POSIXclock_gettime()
。https://en.cppreference.com/w/c/chrono/clock表示:在C11中使用时间规格_get
1.但是,使用
clock_gettime()
可以让您为所需的 * 时钟类型 * 选择所需的时钟ID!***待办事项:
timespec_getres()
在C23之前不受支持,因此请更新我的示例,使其包含一个在Linux上使用POSIXclock_gettime()
和clock_getres()
函数的示例。我希望准确地了解在给定系统上我可以期望的时钟分辨率有多高。**是ms分辨率、us分辨率、ns分辨率还是其他分辨率?**有关参考,请参见:1.答案:
clock_getres()
返回1 ns,但实际分辨率大约为14~27 ns,根据我的get_estimated_resolution()
函数:https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/timinglib.c。在此处查看结果:1.激活Linux
SCHED_RR
软实时循环调度程序,以获得最佳和最一致的定时。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.u4dcyp6a4#
struct timeval包含两个组件,秒和微秒。微秒精度的时间戳表示为从存储在tv_sec字段中的纪元开始的秒数和tv_usec中的小数微秒数。因此,您不能忽略tv_sec并期望得到合理的结果。
如果使用Linux或 *BSD,可以使用timersub()减去两个struct timeval值,这可能是您想要的。
bvjxkvbb5#
来自C11的一个月一个月
返回精度最高为纳秒的值,舍入到实现的分辨率。
更多细节请参见我的另一个答案:How to measure time in milliseconds using ANSI C?
bpzcxfmw6#
但这会返回一些无意义的值,即如果我得到两个时间戳,则第二个时间戳可以比第一个时间戳小或大(第二个时间戳应该总是更大)。
你怎么会这么想呢?这个值可能没问题,这和秒和分的情况是一样的--当你用分和秒来测量时间时,当秒数达到60秒时,秒数就会滚到零。
要将返回值转换为“线性”数字,可以将秒数相乘并加上微秒,但如果我计算正确,一年大约是1 e6 606024360微秒,这意味着需要超过32位来存储结果:
这可能是将原始返回值拆分为两部分的原因之一。
5cnsuln77#
使用unsigned long long(即64位单元)表示系统时间:
8yparm6h8#
迟做总比不做好!这个小程序可以作为获取时间戳(以微秒为单位)和计算进程时间(以微秒为单位)的最快方法:
你可以用一个函数/进程来替换getchar()。最后,你可以把它存储在一个有符号的long中,而不是打印差值。这个程序在Windows 10中运行良好。
g2ieeal79#
首先,我们需要知道微秒的范围,即000_000到999_999(1000000微秒等于1秒)。tv.tv_usec将返回0到999999的值,而不是00000到99999,因此,当使用秒时,我们可能会得到2.1秒,而不是2。000001秒,因为当只讨论tv_usec时,000001本质上是1。如果插入
等等...