以微秒为单位获取C的时间戳?

Kri*_*oks 41 c time

如何在C中获得微秒时间戳?

我正在尝试:

struct timeval tv;
gettimeofday(&tv,NULL);
return tv.tv_usec;
Run Code Online (Sandbox Code Playgroud)

但是这会返回一些无意义的值,如果我得到两个时间戳,第二个可以比第一个更小或更大(第二个应该总是更大).是否可以将gettimeofday返回的魔术整数转换为可以实际使用的正常数字?

unw*_*ind 49

您还需要在几秒钟内添加:

unsigned long time_in_micros = 1000000 * tv.tv_sec + tv.tv_usec;
Run Code Online (Sandbox Code Playgroud)

请注意,这将仅持续约2 32 /10 6 =〜4295秒,或虽然大致71分钟(典型的32位系统).

  • 当然,使用64位整数来存储微秒 (11认同)
  • 问题解决方案:因为你没有从零开始使用tv_sec,所以time_in_micros可以在任何时候翻转!无论是作为单个uint64_t还是作为两个32位值,都不需要64位时间.至少,当您开始计时时,从开始时间保存tv_sec值并从未来的所有计时值中减去它. (2认同)

Rob*_*obᵩ 18

获得微秒时间戳有两种选择.第一个(也是最好的)选择是timeval直接使用类型:

struct timeval GetTimeStamp() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    return tv;
}
Run Code Online (Sandbox Code Playgroud)

第二个,对我来说不太可取的选择是建立一个uint64_t timeval:

uint64_t GetTimeStamp() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    return tv.tv_sec*(uint64_t)1000000+tv.tv_usec;
}
Run Code Online (Sandbox Code Playgroud)

  • @Mooing Duck,对我来说(比你经验不足的程序员),`(uint64_t)1000000`实际上比`1000000ull`更具可读性.现在我已经看到了它们,后者同样有意义,但我会认识到第一个甚至是一个更年轻的编码器,而后者需要我查看它来验证它意味着什么. (5认同)
  • 为什么`(uint64_t)1000000`而不是'1000000ull`? (2认同)
  • ull不能在所有系统上指定完全相同的位数。uintXX_t很好,可以确保您完全得到想要的东西。 (2认同)

Gab*_*les 15

\n

在 C 中获取以微秒为单位的时间戳?

\n
\n

以下是与该问题标题相关的通用答案:

\n

如何在C中获取简单的时间戳

\n
    \n
  1. 以毫秒 (ms) 为单位,函数millis(),
  2. \n
  3. 微秒 (us) 与micros(), 和
  4. \n
  5. 纳秒 (ns) 与nanos()
  6. \n
\n

快速总结:如果您很着急并使用 Linux 或 POSIX 系统,请直接跳到下面标题为“ millis()、 ”micros()和“的部分nanos(),然后使用这些函数。如果您不在Linux 或 POSIX 系统上使用 C11 ,则需要将clock_gettime()这些函数替换为timespec_get().

\n

C 中的 2 个主要时间戳函数:

\n
    \n
  1. C11: timespec_get()C11或更高版本标准的一部分,但不允许选择要使用的时钟类型。它也适用于 C++17。请参阅此处的文档std::timespec_get()。但是,对于 C++11 及更高版本,我更喜欢使用不同的方法,可以指定时钟的分辨率和类型,正如我在此处的答案中演示的那样: Getting an Accuracyexecution Time in C++ (micro Second)

    \n

    C11timespec_get()解决方案比 C++ 解决方案有更多限制,因为您无法指定时钟分辨率或单调性(“单调”时钟被定义为仅向前计数且永远不能向后或跳跃的时钟 - 例如:时间修正)。测量时间差时,需要单调时钟以确保您永远不会将时钟校正跳跃算作“测量”时间的一部分。

    \n

    timespec_get()因此,由于我们无法指定要使用的时钟,因此返回的时间戳值的分辨率可能取决于您的硬件体系结构操作系统编译器通过快速连续进行 1000 次左右的测量,然后找到任意两次后续测量之间的最小差异,可以获得该函数分辨率的近似值。您的时钟的实际分辨率保证等于或小于该最小差异。

    \n

    我在适用于 Linux 的timinglib.cget_estimated_resolution()计时库的函数中演示了这一点。

    \n
  2. \n
  3. Linux 和 POSIX: 甚至timespec_get()C更好的Linux 和 POSIX 函数clock_gettime()function,它在 Linux 或 POSIX 系统上的 C++ 中也能正常工作。clock_gettime() 确实允许您选择所需的时钟。您可以使用 读取指定的时钟分辨率clock_getres(),尽管这也不能为您提供硬件的真实时钟分辨率。相反,它为您提供 的tv_nsec成员的单位struct timespec。使用get_estimated_resolution()上面和我的timinglib.c /.h 文件中描述的函数来获取分辨率的估计值。

    \n
  4. \n
\n

因此,如果您在 Linux 或 POSIX 系统上使用 C,我强烈建议您使用clock_gettime()over timespec_get().

\n

C11 timespec_get()(好的)和 Linux/POSIX clock_gettime()(更好):

\n

以下是这两个功能的使用方法:

\n
    \n
  1. C11 的timespec_get()\n
      \n
    1. https://en.cppreference.com/w/c/chrono/timespec_get
    2. \n
    3. 在 C 语言中工作,但不允许您选择要使用的时钟。
    4. \n
    5. 完整示例,带有错误检查: \n
      #include <stdint.h> // `UINT64_MAX`\n#include <stdio.h>  // `printf()`\n#include <time.h>   // `timespec_get()`\n\n/// Convert seconds to nanoseconds\n#define SEC_TO_NS(sec) ((sec)*1000000000)\n\nuint64_t nanoseconds;\nstruct timespec ts;\nint return_code = timespec_get(&ts, TIME_UTC);\nif (return_code == 0)\n{\n    printf("Failed to obtain timestamp.\\n");\n    nanoseconds = UINT64_MAX; // use this to indicate error\n}\nelse\n{\n    // `ts` now contains your timestamp in seconds and nanoseconds! To \n    // convert the whole struct to nanoseconds, do this:\n    nanoseconds = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;\n}\n
      Run Code Online (Sandbox Code Playgroud)\n
    6. \n
    \n
  2. \n
  3. Linux/POSIX——clock_gettime()尽可能使用这个!\n
      \n
    1. https://man7.org/linux/man-pages/man3/clock_gettime.3.html(此功能的最佳参考)和:
    2. \n
    3. https://linux.die.net/man/3/clock_gettime
    4. \n
    5. 在 Linux 或 POSIX 系统上以 C 语言工作,并允许您选择要使用的时钟!\n
        \n
      1. 我选择CLOCK_MONOTONIC_RAW时钟,它最适合获取用于为系统上的事件计时的时间戳。
      2. \n
      3. 也可以在此处查看所有时钟类型的定义,例如CLOCK_REALTIMECLOCK_MONOTONICCLOCK_MONOTONIC_RAW等: https: //man7.org/linux/man-pages/man3/clock_gettime.3.html
      4. \n
      5. 另一种流行的时钟是CLOCK_REALTIME. 不过,请不要混淆!“实时”并不意味着它是用于“实时”操作系统或精确计时的好时钟。相反,它意味着它是一个时钟,如果时钟漂移,它将定期调整到“实时”或实际的“世界时间”。再次强调,请勿将此时钟用于精确计时,因为系统可以随时向前或向后调整它,而不受您的控制。
      6. \n
      \n
    6. \n
    7. 完整示例,带有错误检查: \n
      // This line **must** come **before** including <time.h> in order to\n// bring in the POSIX functions such as `clock_gettime() from <time.h>`!\n#define _POSIX_C_SOURCE 199309L\n\n#include <errno.h>  // `errno`\n#include <stdint.h> // `UINT64_MAX`\n#include <stdio.h>  // `printf()`\n#include <string.h> // `strerror(errno)`\n#include <time.h>   // `clock_gettime()` and `timespec_get()`\n\n/// Convert seconds to nanoseconds\n#define SEC_TO_NS(sec) ((sec)*1000000000)\n\nuint64_t nanoseconds;\nstruct timespec ts;\nint return_code = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);\nif (return_code == -1)\n{\n    printf("Failed to obtain timestamp. errno = %i: %s\\n", errno, \n        strerror(errno));\n    nanoseconds = UINT64_MAX; // use this to indicate error\n}\nelse\n{\n    // `ts` now contains your timestamp in seconds and nanoseconds! To \n    // convert the whole struct to nanoseconds, do this:\n    nanoseconds = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;\n}\n
      Run Code Online (Sandbox Code Playgroud)\n
    8. \n
    \n
  4. \n
\n

millis()micros(), 和nanos()

\n

不管怎样,这里是我在 C 中使用的millis()micros()、 和函数,用于简单的时间戳和代码速度分析。nanos()

\n

我正在使用下面的 Linux/POSIXclock_gettime()函数。如果您在不可用的系统上使用 C11 或更高版本,只需将下面clock_gettime()的所有用法替换为即可。clock_gettime(CLOCK_MONOTONIC_RAW, &ts)timespec_get(&ts, TIME_UTC)

\n

从我的eRCaGuy_hello_world存储库获取最新版本的代码:

\n
    \n
  1. 时序库
  2. \n
  3. 时序库c
  4. \n
\n
// This line **must** come **before** including <time.h> in order to\n// bring in the POSIX functions such as `clock_gettime() from <time.h>`!\n#define _POSIX_C_SOURCE 199309L\n        \n#include <time.h>\n\n/// Convert seconds to milliseconds\n#define SEC_TO_MS(sec) ((sec)*1000)\n/// Convert seconds to microseconds\n#define SEC_TO_US(sec) ((sec)*1000000)\n/// Convert seconds to nanoseconds\n#define SEC_TO_NS(sec) ((sec)*1000000000)\n\n/// Convert nanoseconds to seconds\n#define NS_TO_SEC(ns)   ((ns)/1000000000)\n/// Convert nanoseconds to milliseconds\n#define NS_TO_MS(ns)    ((ns)/1000000)\n/// Convert nanoseconds to microseconds\n#define NS_TO_US(ns)    ((ns)/1000)\n\n/// Get a time stamp in milliseconds.\nuint64_t millis()\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);\n    uint64_t ms = SEC_TO_MS((uint64_t)ts.tv_sec) + NS_TO_MS((uint64_t)ts.tv_nsec);\n    return ms;\n}\n\n/// Get a time stamp in microseconds.\nuint64_t micros()\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);\n    uint64_t us = SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec);\n    return us;\n}\n\n/// Get a time stamp in nanoseconds.\nuint64_t nanos()\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);\n    uint64_t ns = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;\n    return ns;\n}\n\n// NB: for all 3 timestamp functions above: gcc defines the type of the internal\n// `tv_sec` seconds value inside the `struct timespec`, which is used\n// internally in these functions, as a signed `long int`. For architectures\n// where `long int` is 64 bits, that means it will have undefined\n// (signed) overflow in 2^64 sec = 5.8455 x 10^11 years. For architectures\n// where this type is 32 bits, it will occur in 2^32 sec = 136 years. If the\n// implementation-defined epoch for the timespec is 1970, then your program\n// could have undefined behavior signed time rollover in as little as\n// 136 years - (year 2021 - year 1970) = 136 - 51 = 85 years. If the epoch\n// was 1900 then it could be as short as 136 - (2021 - 1900) = 136 - 121 =\n// 15 years. Hopefully your program won\'t need to run that long. :). To see,\n// by inspection, what your system\'s epoch is, simply print out a timestamp and\n// calculate how far back a timestamp of 0 would have occurred. Ex: convert\n// the timestamp to years and subtract that number of years from the present\n// year.\n
Run Code Online (Sandbox Code Playgroud)\n

时间戳分辨率:

\n

在我的带有 gcc 编译器的 x86-64 Linux Ubuntu 18.04 系统上,clock_getres()返回分辨率为1 ns

\n

对于 和clock_gettime()timespec_get()我还进行了实证测试,我尽可能快地快速获取 1000 个时间戳(请参阅get_estimated_resolution()我的Timinglib.c计时库的函数),并查看时间戳样本之间的最小间隙是多少。这表明我的系统上使用和 时的范围为~14~26 ns,使用 时为~75~130 ns。这可以被认为是这些函数的粗略“实际解决方案”。请参阅 中的测试代码,并查看 中 my和函数(由该测试代码使用)的定义。timespec_get(&ts, TIME_UTC)clock_gettime(CLOCK_MONOTONIC, &ts)clock_gettime(CLOCK_MONOTONIC_RAW, &ts)timinglib_get_resolution.cget_estimated_resolution()get_specified_resolution()timinglib.c

\n

这些结果是特定于硬件的,并且您的硬件上的结果可能会有所不同。

\n

参考:

\n
    \n
  1. 我在上面链接到的 cppreference.com 文档源。
  2. \n
  3. @Ciro Santilli\xe6\x96\xb0\xe7\x96\x86\xe6\xa3\x89\xe8\x8a\xb1 的答案
  4. \n
  5. [我的答案]我的答案关于usleep()nanosleep()- 它提醒我我需要做#define _POSIX_C_SOURCE 199309L才能引入clock_gettime()POSIX 函数<time.h>
  6. \n
  7. https://linux.die.net/man/3/clock_gettime
  8. \n
  9. https://man7.org/linux/man-pages/man3/clock_gettime.3.html \n
      \n
    1. 提到了以下要求:
    2. \n
    \n
    \n

    _POSIX_C_SOURCE >= 199309L

    \n
    \n
      \n
    1. 请参阅此处所有时钟类型的定义,例如CLOCK_REALTIMECLOCK_MONOTONICCLOCK_MONOTONIC_RAW等。
    2. \n
    \n
  10. \n
\n

也可以看看:

\n
    \n
  1. 我在这里的简短且不太通俗的答案仅适用于 ANSI/ISO C11 或更高版本:How tomeasure time in milliseconds using ANSI C?
  2. \n
  3. 我的 3 组时间戳函数(相互交叉链接):\n
      \n
    1. 对于C 时间戳,请参阅我的答案:Get a timestamp in C in microseconds?
    2. \n
    3. 对于C++ 高分辨率时间戳,请参阅我的答案:Here is how to get simple C-like millisecond, microsecond, and nanosecond timestamps in C++
    4. \n
    5. 对于Python高分辨率时间戳,请参阅我的答案:How can I get millisecond and microsecond-resolve timestamps in Python?
    6. \n
    \n
  4. \n
  5. https://en.cppreference.com/w/c/chrono/clock \n
      \n
    1. POSIX clock_gettime()https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
    2. \n
    \n
  6. \n
  7. clock_gettime()在 Linux 上: https: //linux.die.net/man/3/clock_gettime \n
      \n
    1. 注意:对于 C11 及更高版本,您可以使用timespec_get(),就像我上面所做的那样,而不是 POSIX clock_gettime()https://en.cppreference.com/w/c/chrono/clock说:\n
      \n

      在 C11 中使用 timespec_get

      \n
      \n
    2. \n
    3. 但是,使用它可以让您为您想要的时钟类型clock_gettime()选择所需的时钟 ID !另请参阅此处: ***** https://people.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html
    4. \n
    \n
  8. \n
\n

去做:

\n
    \n
  1. \xe2\x9c\x93 于 2022 年 4 月 3 日完成:由于在C23 之前不受支持,因此更新我的示例以包括在 Linux 上timespec_getres()使用 POSIXclock_gettime()和函数的示例。clock_getres()我想确切地知道在给定系统上我期望的时钟分辨率有多好。是 ms 分辨率、us 分辨率、ns 分辨率还是其他分辨率?如需参考,请参阅:\n
      \n
    1. https://linux.die.net/man/3/clock_gettime
    2. \n
    3. https://people.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html
    4. \n
    5. https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
    6. \n
    7. 答案:clock_getres()返回1 ns,但实际分辨率约为14~27 ns,根据我的get_estimated_resolution()函数: https: //github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/timinglib.c。在此处查看结果:\n
        \n
      1. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/timinglib_get_resolution.c#L46-L77
      2. \n
      3. 激活 LinuxSCHED_RR软实时循环调度程序,以获得最佳且最一致的计时。请参阅我的答案clock_nanosleep()如何配置 Linux SCHED_RR 软实时循环调度程序,以便clock_nanosleep()可以将分辨率从约 55 us 提高到约 4 us
      4. \n
      \n
    8. \n
    \n
  2. \n
\n


jan*_*neb 8

struct timeval包含两个组件,第二个和微秒.具有微秒精度的时间戳表示为自tv_sec字段中存储的纪元以及tv_usec中的小数微秒以来的秒数.因此,你不能只是忽略tv_sec并期待合理的结果.

如果使用Linux或*BSD,则可以使用timersub()减去两个struct timeval值,这可能是您想要的.


Cir*_*四事件 6

timespec_get 来自 C11

以最高纳秒的精度返回,四舍五入到实现的分辨率。

#include <time.h>
struct timespec ts;
timespec_get(&ts, TIME_UTC);
struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};
Run Code Online (Sandbox Code Playgroud)

更多细节在这里:https : //stackoverflow.com/a/36095407/895245