【问题标题】:What is the precision of the gettimeofday function?gettimeofday 函数的精度是多少?
【发布时间】:2021-09-08 08:40:52
【问题描述】:

我正在阅读 OSTEP 的 single.dvi 章节。在作业部分,它说:

您必须考虑的一件事是计时器的精度和准确性。您可以使用的典型计时器是gettimeofday(); 阅读手册页了解详细信息。你会看到gettimeofday() 返回自 1970 年以来的时间(以微秒为单位);然而,这并不意味着 计时器精确到微秒。测量背靠背呼叫 到gettimeofday() 了解计时器的精确度 盟友是;这将告诉您空系统调用的迭代次数 测试您必须运行才能获得良好的测量结果。如果 gettimeofday() 对你来说不够精确,你可以看看 使用 x86 机器上可用的 rdtsc 指令

我写了一些代码来测试调用gettimeofday()函数的成本如下:

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

#define MAX_TIMES 100000

void m_gettimeofday() {
    struct timeval current_time[MAX_TIMES];
    int i;
    for (i = 0; i < MAX_TIMES; ++i) {
        gettimeofday(&current_time[i], NULL);
    }
    printf("seconds: %ld\nmicro_seconds: %ld\n", current_time[0].tv_sec, current_time[0].tv_usec);
    printf("seconds: %ld\nmicro_seconds: %ld\n", current_time[MAX_TIMES - 1].tv_sec, current_time[MAX_TIMES - 1].tv_usec);
    printf("the average time of a gettimeofday function call is: %ld us\n", (current_time[MAX_TIMES - 1].tv_usec - current_time[0].tv_usec) / MAX_TIMES);
}

int main(int argc, char *argv[]) {
    m_gettimeofday();
    return 0;
}

但是,输出将始终为 0 微秒。 gettimeofday() 函数的精度似乎正好是一微秒。我的测试代码有什么问题?还是我误解了作者的意思?感谢您的帮助!

【问题讨论】:

  • pubs.opengroup.org/onlinepubs/9699919799/functions/… ==> "未指定系统时钟的分辨率。"和“应用程序应该使用 clock_gettime() 函数而不是过时的 gettimeofday() 函数。”
  • 这是否意味着函数的准确性是不确定的?
  • 您可以在CLOCK_REALTIME 时钟上使用clock_getres 函数来获得以纳秒为单位的分辨率。
  • 一个不保证准确的函数仍然可能给出完全准确的结果。不能依靠它来做到这一点。
  • POSIX 未指定分辨率。并不意味着您的环境未指定它。在您的计算机中,对于您当前版本的操作系统/C 库,它是一个特定值;您需要检查您的文档。

标签: c gettimeofday


【解决方案1】:

连续调用gettimeofday 之间经过的平均微秒通常小于一 - 在我的机器上它介于 0.05 和 0.15 之间。

现代 CPU 通常以 GHz 速度运行 - 即每秒 十亿 条指令,因此两条连续的指令应该采用纳秒量级,而不是微秒量级(显然两次调用类似 @987654323 的函数@ 比两个简单的操作码更复杂,但它仍应在几十纳秒的数量级上,而不是更多)。

但是您正在执行ints 的除法——将(current_time[MAX_TIMES - 1].tv_usec - current_time[0].tv_usec) 除以MAX_TIMES——在C 中也将返回int,在本例中为0。


要获得真正的测量值,请除以(double)MAX_TIMES(并将结果打印为双精度数):

printf("the average time of a gettimeofday function call is: %f us\n", (current_time[MAX_TIMES - 1].tv_usec - current_time[0].tv_usec) / (double)MAX_TIMES);

作为奖励 - 在 Linux 系统上,gettimeofday 如此之快的原因(您可能会认为它是一个更复杂的函数,调用内核并产生系统调用的开销)要归功于称为 @ 的特殊功能987654321@ 让内核无需通过内核就可以向用户空间提供信息。

【讨论】:

  • 这是否意味着我的机器上的 getTimeofday 没有准确性问题?虽然我知道我应该使用 clock_gettime 来代替它。
  • 是的,您只需要修正计算平均值的方式即可。
【解决方案2】:

gettimeofday(2) 代表 clock_gettime(2) 被宣布过时,其分辨率比旧版本更好(它使用纳秒分辨率)

精度是另一个问题(不同),它取决于硬件如何允许您获取时间戳以及操作系统如何实现它。

在基于 linux/intel 的系统中,通常有很好的硬件可用,并且由 linux 很好地实现,因此在处理时间戳时通常可以获得真正的纳秒精度。但不要试图在石英振荡器质量差且未经过 PPS sincronized 的机器中获得这种精度。您没有指定需要获取什么样的时间戳,但是如果您需要获取绝对时间戳,与官方时间进行比较,不要期望它们接近几百毫秒(基于 NTP 同步用普通石英振荡器的机器)

无论如何,要获得您安排的通话的平均时间,您有两个问题:

  • 您需要调用 MAX_TIMES + 1 乘以 gettimeofday(2) 系统调用,因为您正在测量两个时间戳之间的时间(因此您计算调用系统调用之间的时间并且它能够获取时间戳,并且从时间戳到返回值的时间被传递给调用例程---但顺序相反)最好的方法是在开头使用时间戳t0,在@987654327中使用MAX_TIMES时间戳@ 在末尾。只有这样,您才能确定t0t1 之间的时间并将其划分为MAX_TIMES。为此,从t1.tv_usec 中减去t0.tv_usec,如果结果小于零,则将1000000 添加到其中,并增加t1.tv_sec - t0.tv_sec 的差值。 tv_sec 会有秒的差异,tv_usec 会有超过秒的微秒。
  • 这假设系统调用开销不变,但事实并非如此。有时系统调用的时间比别人多,你感兴趣的值不是它们的平均值,而是它能达到的最小值。但是您可以遵循平均水平,因为您不会进入低于 usec 的分辨率。

无论如何,我建议您使用clock_gettime(2) 系统调用,因为它具有纳秒级分辨率。

【讨论】:

    猜你喜欢
    • 2012-10-25
    • 2016-01-07
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    相关资源
    最近更新 更多