【问题标题】:Measuring short time intervals in C on Ubuntu / VMware在 Ubuntu / VMware 上用 C 语言测量短时间间隔
【发布时间】:2012-01-28 20:49:35
【问题描述】:

我正在尝试测量短时间间隔,以几毫秒为单位。这被证明是一项不平凡的任务,因为无处不在的 time() 函数以整秒精度工作。经过一番研究,我得出了以下代码示例中的四种方法:

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

int main(int argc, char *argv[])
{
    clock_t t0, t1;
    double dt0;

    struct timespec t2, t3;
    double dt1;

    struct timespec t4, t5;
    double dt2;

    struct timeval t6, t7;
    double dt3;

    volatile long long i;

    t2.tv_sec = 0;
    t2.tv_nsec = 0;
    clock_settime(CLOCK_MONOTONIC, &t2);
    clock_settime(CLOCK_REALTIME,  &t2);

    t0 = clock();
    clock_gettime(CLOCK_REALTIME,  &t2);
    clock_gettime(CLOCK_MONOTONIC, &t4);
    gettimeofday(&t6, NULL);

    getchar();
    for (i=0; i<1e9; i++) {};

    gettimeofday(&t7, NULL);
    clock_gettime(CLOCK_MONOTONIC, &t5);
    clock_gettime(CLOCK_REALTIME,  &t3);
    t1 = clock();

    dt0 = (double) (t1 - t0) / CLOCKS_PER_SEC;
    dt1 = (double) (t3.tv_nsec - t2.tv_nsec) / 1e9;
    dt2 = (double) (t5.tv_nsec - t4.tv_nsec) / 1e9;
    dt3 = (double) (t7.tv_usec - t6.tv_usec) / 1e6;

    printf("1. clock():          [0]=%10.0f, [1]=%10.0f, [1-0]=%10.6f sec\n", (double) t0, (double) t1, dt0);
    printf("2. clock_gettime(R): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t2.tv_nsec, (long) t3.tv_nsec, dt1);
    printf("3. clock_gettime(M): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t4.tv_nsec, (long) t5.tv_nsec, dt2);
    printf("4. gettimeofday():   [4]=%10ld, [5]=%10ld, [5-4]=%10f sec\n", (long) t6.tv_usec, (long) t7.tv_usec, dt3);

    return 0;
}

然后,我编译并运行它:

gcc -lrt -o timer.e timer.c; time ./timer.e

我使用getchar() 调用引入了几秒钟的延迟,以查看real 和user 时间报告之间的差异,结果是:

1. clock():          [0]=         0, [1]=   3280000, [1-0]=  3.280000 sec
2. clock_gettime(R): [2]= 823922476, [3]= 478650549, [3-2]= -0.345272 sec
3. clock_gettime(M): [2]= 671137949, [3]= 325864897, [3-2]= -0.345273 sec
4. gettimeofday():   [4]=    823924, [5]=    478648, [5-4]= -0.345276 sec

real    0m6.659s
user    0m3.280s
sys     0m0.010s

如您所见,唯一有意义的结果是方法1与time命令报告的user时间之间的相关性。

这带来了几个问题: 1. 为什么结果 2-4 没有意义? 2. 如何衡量运行程序所花费的实际时间,例如real 数字time 报告?

我的环境是基于 AMD 的 HP 笔记本电脑上的 Windows 7 上的 VMware 上的 Ubuntu 10.04 LTS 64 位。

【问题讨论】:

  • 如果这是出于测试目的,您可能会发现增加迭代次数很有帮助。这当然会使测试运行时间更长,但可以使用分辨率较低的时序测量。
  • @MichaelMior - 它用于非常粗略的基准测试 - 我正在尝试比较在主机(linux)和通过 USB 连接的硬件加速器上执行的某些算法的运行时间。在这两种情况下,调用者都是同一个程序,即宿主程序,我需要一种方法来获取它只是“等待”外部硬件完成其工作的总时间。这就是为什么 clock() 不是答案,b/c 它不计入等待时间(如 getchar() 调用所示)。

标签: c time measurement


【解决方案1】:

clock_gettime() 让您走在正确的轨道上。

但是,您应该摆脱那些clock_settime() 调用:只需在代码块之前和之后调用clock_gettime(),然后看看区别。

另外,在计算差值时,您应该同时考虑tv_sec 和tv_nsec;您当前的代码只查看纳秒部分并忽略整秒。

在我的 Ubuntu 系统上,以下代码非常准确地测量了执行循环所需的时间:

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

int main(int argc, char *argv[])
{
    struct timespec t2, t3;
    double dt1;

    volatile long long i;

    clock_gettime(CLOCK_MONOTONIC,  &t2);
    for (i=0; i<1e9; i++) {};
    clock_gettime(CLOCK_MONOTONIC,  &t3);
    //time in seconds
    dt1 = (t3.tv_sec - t2.tv_sec) + (double) (t3.tv_nsec - t2.tv_nsec) * 1e-9;
    printf("%f\n", dt1);

    return 0;
}

【讨论】:

  • 谢谢!这个更正做了我正在寻找的东西。每隔一段时间,人们就会错过看到显而易见的事情。我以为 _sec 和 _nsec 字段以不同的精度处理相同的数据,但现在我看到它是时间戳的整体和纳秒部分。
【解决方案2】:

关于将时间测量到微秒甚至纳秒的一些提示http://en.wikipedia.org/wiki/Time_Stamp_Counter

【讨论】:

  • 感谢您指出关于 rdtsc 的解释。在某些情况下可能有用,但我试图弄清楚为什么我编写的代码没有给出预期的结果。
【解决方案3】:

您的clock_settime 调用与您认为的不同。如果您获得许可,他们只需将系统范围的时钟设置为0,这可能不是您想要的。几乎所有 POSIX 函数都有一个返回值,告诉您调用是否成功。通常忽略该值是一个坏主意。特别是对于您的情况,我认为它应该给出这个值,因为它可以在man 页面中找到:

EPERM clock_settime() 没有设置时钟的权限 表示。

幸运的是,您没有权限像这样简单地设置时钟:)

【讨论】:

  • 我在收到 gettime 的奇怪结果后添加了 settime。显然,它对结果没有任何影响。
  • @ysap,这正是我要说的。它对结果没有影响,因为 它失败了。否则,它将对您的机器产生巨大的影响,将您的系统时钟设置为 1970 年 1 月 1 日左右。不要那样做。检查系统调用的返回是否成功。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-25
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 2013-03-28
  • 1970-01-01
相关资源
最近更新 更多