clock_gettime() 是否在 MinGW GCC 8.2.0 中正确实施?

Is clock_gettime() correctly implemented in MinGW GCC 8.2.0?

一个偶然的机会,我发现 Linux 系统存在 clock_gettime() 功能。因为我正在寻找一种方法来测量函数的执行时间,所以我在 Windows 10 64 位机器上的 MinGW gcc 8.2.0 版本中尝试了它:

#include <time.h>
#include <stdio.h>

int main() {
    struct timespec tstart, tend;
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tstart);
    for (int i = 0; i < 100000; ++i);
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tend);
    printf("It takes %li nanoseconds for 100,000 empty iterations.\n", tend.tv_nsec - tstart.tv_nsec);
    return 0;
}

此代码片段在没有 warnings/errors 的情况下编译,并且没有运行时失败(至少没有写入标准输出)。

输出:

It takes 0 nanoseconds for 100,000 empty iterations.

我不相信这是真的。

你能找出漏洞吗?


还有一件事:

根据 ISO/IEC 9899:201x 的 N1570 Committee draft(2011 年 4 月 12 日),timespec_get() 不应该代替 clock_gettime()

那个循环应该优化到什么都没有,所以使用低分辨率时钟(分辨率不一定是单个纳秒;它可能会以更大的单位前进,clock_getres 应该可以告诉你) 0 是一个合理的结果。但是您的代码中还有一些其他错误,例如将 CLOCK_THREAD_CPUTIME_IDCLOCK_PROCESS_CPUTIME_ID 混合使用并且不检查 clock_gettime 的 return 值(它可能告诉您这些时钟不是支持)。

首先,您的代码正在查询两个不同的时钟(CLOCK_THREAD_CPUTIME_ID 用于 tstartCLOCK_PROCESS_CPUTIME_ID 用于 tend),因此比较两个值。其次,您只查看由 clock_gettime() 编辑的 struct timespec return 的 tv_nsec 字段,即使两次查询相同的时钟,您的差异也可能是错误的。此外,您的编译器可能正在优化空的 for 循环,但如果不查看生成的二进制文件就无法说出这一点,但我发现这不太可能,除非您使用 -O1 或 [=19= 进行编译](例如,参见 here,仅使用 -O2 即可消除循环)。

此外,Windows 根本不符合 POSIX,MinGW 只能在某种程度上模仿 clock_gettime() 的行为,所以我不会真的相信它 return精确值。 mingw-w64 looking at the source code 好像没问题,但不知道你用的是不是那个版本。尽管 struct timespec 对象以纳秒分辨率描述时间,但可用分辨率取决于系统,甚至可能大于 1 秒。你可能想看看 clock_getres() 说的是什么。

According to the N1570 Committee draft (April 12, 2011) of the ISO/IEC 9899:201x, shouldn't timespec_get() take the role of clock_gettime() instead?

C 标准没有说明任何关于哪个函数应该扮演另一个函数的角色。 timespec_get() 函数确实 而不是 具有与 clock_gettime() 相同的语义。 timespec_get() 函数仅适用于“日历时间”(使用 clock_gettime() 时应与 CLOCK_REALTIME 相同)。