【问题标题】:Measuring time in millisecond precision以毫秒精度测量时间
【发布时间】:2013-05-26 22:27:56
【问题描述】:

我的程序将在时间和空间上相互竞争不同的排序算法。我已经占满了空间,但是测量时间给我带来了一些麻烦。这是运行排序的代码:

void test(short* n, short len) {
  short i, j, a[1024];

  for(i=0; i<2; i++) {         // Loop over each sort algo
    memused = 0;               // Initialize memory marker
    for(j=0; j<len; j++)       // Copy scrambled list into fresh array
      a[j] = n[j];             // (Sorting algos are in-place)
                               // ***Point A***
    switch(i) {                // Pick sorting algo
    case 0:
      selectionSort(a, len);
    case 1:
      quicksort(a, len);
    }
                               // ***Point B***    
    spc[i][len] = memused;     // Record how much mem was used
  }
}

(为简单起见,我删除了一些排序算法)

现在,我需要测量排序算法需要多少时间。最明显的方法是记录 (a) 点的时间,然后从 (b) 点的时间中减去该时间。但是没有一个 C 时间函数足够好:

time() 给了我以秒为单位的时间,但算法比这更快,所以我需要更准确的东西。

clock() 给了我自程序启动以来的 CPU 滴答声,但似乎四舍五入到最接近的 10,000;还是不够小

time shell 命令运行良好,但我需要为每个算法运行超过 1,000 次测试,而且我需要为每个算法设置单独的时间。

我不知道 getrusage() 返回什么,但它也太长了。

我需要的是比排序函数的运行时间更小的单位时间(如果可能的话,显着地):大约 2 毫秒。所以我的问题是:我在哪里可以得到它?

【问题讨论】:

  • 哪个平台?提及getrusage() 建议使用POSIX 系统,在这种情况下gettimeofday()clock_gettime() 是合适的(分别为微秒和纳秒分辨率,不一定具有规定的精度)。
  • man 2 clock_gettime,或者,如果你可以使用 C 2011,int timespec_get(struct timespec *ts, int base);
  • 平台:AMD Athlon 64(运行 Debian Linux)

标签: c time


【解决方案1】:

要测量时间,请使用clock_gettimeCLOCK_MONOTONIC(或CLOCK_MONOTONIC_RAW,如果可用)。尽可能避免使用gettimeofday。它特别反对clock_gettime,并且从它返回的时间会受到时间服务器的调整,这可能会影响您的测量。

【讨论】:

    【解决方案2】:

    您可以使用getrusage 获取总用户 + 内核时间(或仅选择一个),如下所示:

    #include <sys/time.h>
    #include <sys/resource.h>
    
    double get_process_time() {
        struct rusage usage;
        if( 0 == getrusage(RUSAGE_SELF, &usage) ) {
            return (double)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) +
                   (double)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / 1.0e6;
        }
        return 0;
    }
    

    我选择创建一个包含小数秒的double...

    double t_begin, t_end;
    
    t_begin = get_process_time();
    // Do some operation...
    t_end = get_process_time();
    
    printf( "Elapsed time: %.6f seconds\n", t_end - t_begin );
    

    【讨论】:

      【解决方案3】:

      gettimeofday() 具有微秒级分辨率,易于使用。

      一对有用的定时器函数是:

      static struct timeval tm1;
      
      static inline void start()
      {
          gettimeofday(&tm1, NULL);
      }
      
      static inline void stop()
      {
          struct timeval tm2;
          gettimeofday(&tm2, NULL);
      
          unsigned long long t = 1000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec) / 1000;
          printf("%llu ms\n", t);
      }
      

      【讨论】:

      • @OliCharlesworth 不幸的是没有,但至少它通常提供了一个很好的近似值。当然,这 10 行左右的代码不能写出好的产品代码,但这也不是我的目标。
      • 微秒是 µs(使用 ascii 代码 230 -- '\181' 八进制),而不是 ms(代表毫秒)。它通常用 u 而不是 mu 编写:us.
      • @paddy Euh...我是否断言了一些反对的东西?
      • 哦,抱歉,我看错了,还以为你输出的是微秒。
      • 是的,不要使用gettimeofday。它受时间服务器更新和漂移的影响。
      【解决方案4】:

      时间戳计数器在这里可能会有所帮助:

      static unsigned long long rdtsctime() {
          unsigned int eax, edx;
          unsigned long long val;
          __asm__ __volatile__("rdtsc":"=a"(eax), "=d"(edx));
          val = edx;
          val = val << 32;
          val += eax;
          return val;
      }
      

      尽管对此有一些警告。不同处理器内核的时间戳可能不同,并且更改时钟速度(由于节能功能等)可能会导致错误的结果。

      【讨论】:

      • 假设您使用的是 Intel/AMD x86_64 平台,而不是 SPARC、PPC、PA-RISC(也可能不是 IA-64)。
      • 我相信从 Pentium 4 开始,TSC 与瞬时 CPU 频率无关(参见 Intel-64 SDM 的第 17.12 章)。
      • 即使使用基于 Intel 的系统,也不需要 CPU 特定指令来解决上述原始问题。如果处理得当,比较排序算法(根本)不需要这种类型的粒度。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 2014-03-20
      • 2020-03-18
      • 2011-12-30
      • 2017-08-31
      • 1970-01-01
      相关资源
      最近更新 更多