C语言 gettimeofday函数的精度是多少?

camsedfj  于 2023-03-12  发布在  其他
关注(0)|答案(3)|浏览(328)

我正在阅读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()函数的精度正好是1微秒,我的测试代码是哪里出了问题,还是误解了作者的意思,谢谢帮助!

2mbi3lxu

2mbi3lxu1#

gettimeofday的连续调用之间的平均微秒数通常小于1-在我的机器上,它介于0.05和0.15之间。
现代CPU通常以GHz的速度运行--即每秒 * 数十亿 * 条指令,因此两条连续的指令应该花费纳秒级的时间,而不是微秒级的时间(显然,对gettimeofday这样的函数的两次调用比两个简单的操作码更复杂,但它仍然应该花费数十纳秒级的时间,而不是更多)。
但是你正在执行int s的除法--(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之所以如此之快(您可能会认为它是一个更复杂的函数,需要调用内核并产生系统调用的开销),是由于一个名为vdso的特殊特性,该特性允许内核向用户空间提供信息,而根本不需要通过内核。

68bkxrlz

68bkxrlz2#

gettimeofday(2)被宣布为过时,代表clock_gettime(2)具有比旧版本更好的分辨率(它使用纳秒分辨率)
精确度是另一个问题(不同),因为它取决于硬件如何允许您获得时间戳以及操作系统如何实现它。
在基于linux/intel的系统中,通常有很好的硬件可用,并且它在linux中实现得很好,所以通常你可以在处理时间戳时获得真正的纳秒精度。但是不要试图在石英振荡器很差并且没有PPS集成的机器中获得这个精度。你不需要指定你需要获取什么类型的时间戳,但是如果你需要获取绝对时间戳,为了与官方时间比较,不要期望它们接近于几百毫秒(基于带有普通石英振荡器的NTP同步机器)
无论如何,要获得您安排的呼叫的平均时间,您有两个问题:

  • 您需要调用MAX_TIMES + 1乘以您的gettimeofday(2)系统调用,因为您正在测量两个时间戳之间的时间(因此您计算调用系统调用和它能够获取时间戳之间的时间,并且从时间戳到返回值的时间被传递给调用例程---但顺序相反)最好的方法是在开始处取一个时间戳t0,在结束处取t1中的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)系统调用,因为它具有纳秒级的分辨率。

h6my8fg2

h6my8fg23#

z=x=gettimeofday()
    for(i=1; x==z; i++){ z=gettimeofday()}
    # >10,000 loops until diff gettimeofday()
    y=sprintf("%.24f",z-x);
    #: 0.015600204 = diff gettimeofday() on my desktop. Your mileage may vary.
    #:     ^  ^  ^
    #: ns=nanosecond= 10^-9; 1/1,000,000,000=> fmt=".9f"
    #: us=microsecond= 10^-6; 1/1,000,000=> fmt=".6f"
    #: ms=millisecond= 10^-3; 1/1,000 => fmt=".3f"

相关问题