2

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

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

我写了一些代码来测试调用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()恰好是一微秒。我的测试代码有什么问题?还是我误解了作者的意思?谢谢您的帮助!

4

2 回答 2

4

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

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

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


要获得真正的测量值,请除以(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的特殊功能,它允许内核提供信息到用户空间,根本不经过内核。

于 2021-09-08T08:48:24.837 回答
2

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

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

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

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

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

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

于 2021-09-10T11:11:11.117 回答