【问题标题】:clock() precision in time.h时钟() time.h 精度
【发布时间】:2012-01-25 12:40:21
【问题描述】:

我正在尝试计算函数用于运行的刻度数,并使用clock() 函数来执行此操作,如下所示:

unsigned long time = clock();
myfunction();
unsigned long time2 = clock() - time;
printf("time elapsed : %lu",time2);

但问题是它返回的值是10000的倍数,我认为是CLOCK_PER_SECOND。有没有更精确的方法或等效函数值?

我正在使用 Ubuntu 64 位,但如果该解决方案可以在 Windows 和 Mac OS 等其他系统上运行,我更愿意。

【问题讨论】:

  • 将变量命名为 time 不是一个好主意,尤其是在您使用 <time.h> 时,因为有一个使用该名称的标准函数。
  • 我使用时间作为变量名只是为了问题的目的。

标签: c linux time clock


【解决方案1】:

POSIX 中有许多更精确的计时器。

  • gettimeofday() - 正式过时,但非常普遍;微秒级分辨率。
  • clock_gettime() - gettimeofday() 的替代品(但不一定广泛使用;在旧版本的 Solaris 上,需要 -lposix4 链接),具有纳秒级分辨率。

还有其他亚秒级计时器或多或少的古老、便携性和分辨率,包括:

  • ftime() - 毫秒分辨率(在 POSIX 2004 中标记为“旧版”;在 POSIX 2008 中没有)。
  • clock() - 你已经知道了。请注意,它测量的是 CPU 时间,而不是经过的(挂钟)时间。
  • times() - CLK_TCKHZ。请注意,这会测量父进程和子进程的 CPU 时间。

除非没有更好的办法,否则不要使用ftime()times()。最终的回退,但不能满足您的直接要求,是

clock() 函数以CLOCKS_PER_SEC 为单位进行报告,POSIX 要求其为1,000,000,但增量发生的频率可能较低(每秒 100 次是一种常见频率)。返回值必须由CLOCKS_PER_SEC 定义,以秒为单位获取时间。

【讨论】:

  • 嗯,它在 Solaris 上可用的事实是一件好事。又一个努力实现 POSIX 合规性的操作系统。话虽如此,POSIX 是否不要求该符号至少可用于-lrt
  • 我在不久前写了这些笔记——也许是 Solaris 2.6 时代(嗯……1998……是的,很久以前!)。所以所需的库可能已经改变了。
  • @jørgensen:该链接指向 POSIX 2008,它仍被列为 POSIX 的一部分,尽管自第 7 期(这是POSIX 2008 标准)以来已被标记为过时;请参阅链接到的页面标题)。因此,我认为您宣布 gettimeofday() 已过时还为时过早;它仍然过时了。
  • @JonathanLeffler clock() 在 x86 平台上运行的 Linux 上也有 1 秒的分辨率。它每秒增加 10,000 次。
  • @JenniferAnderson:我认为 Linux 上的 clock() 可能有 1/100 秒的分辨率。 CLOCKS_PER_SEC 必须为 1,000,000(并且在 RedHat 5.3 的 /usr/include/time.h 中如此定义)。你提到增加了10,000;这必须每秒执行 100 次才能达到每秒增加 1,000,000 次所需的速率。还要注意,clock() 测量的是 CPU 时间,而不是经过的时间。 (有关更多信息,请参阅Sorting 2 arrays using 2 threads takes more time than sorting the 2 arrays one at a time。)
【解决方案2】:

测量时间的最精确(但高度便携)的方法是计算 CPU 滴答声。

例如在 x86 上

 unsigned long long int asmx86Time ()
 {
   unsigned long long int realTimeClock = 0;
   asm volatile ( "rdtsc\n\t"         
                  "salq $32, %%rdx\n\t"    
                  "orq %%rdx, %%rax\n\t"   
                  "movq %%rax, %0"         
                  : "=r" ( realTimeClock ) 
                  : /* no inputs */
                  : "%rax", "%rdx" );
   return realTimeClock;
 }

 double cpuFreq ()
 {
   ifstream file ( "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" );
   string sFreq; if ( file ) file >> sFreq;
   stringstream ssFreq ( sFreq ); double freq = 0.;
   if ( ssFreq ) { ssFreq >> freq; freq *= 1000; } // kHz to Hz
   return freq;
 }

 // Timing

 unsigned long long int asmStart = asmx86Time ();
 doStuff ();
 unsigned long long int asmStop  = asmx86Time ();
 float asmDuration = ( asmStop - asmStart ) / cpuFreq ();

如果您没有 x86,则必须根据您的 CPU 重新编写汇编代码。如果您需要最大精度,不幸的是,这是唯一的方法......否则使用clock_gettime()。

【讨论】:

    【解决方案3】:

    根据 clock() 手册页,在 POSIX 平台上,CLOCKS_PER_SEC 宏的值必须为 1000000。正如您所说,您从 clock() 获得的返回值是 10000 的倍数,这意味着分辨率为 10 毫秒。

    另请注意,Linux 上的 clock() 返回程序使用的处理器时间的近似值。同样,在 Linux 上,调度器统计信息会在调度器运行时以 CONFIG_HZ 频率更新。因此,如果周期性计时器滴答频率为 100 Hz,您将获得分辨率为 10 ms 的进程 CPU 时间消耗统计信息。

    Walltime 测量不受此限制,并且可以更加准确。现代 Linux 系统上的 clock_gettime(CLOCK_MONOTONIC, ...) 提供纳秒级分辨率。

    【讨论】:

    • 感谢大家的回答,我可以使用clock_gettime。
    【解决方案4】:

    我同意乔纳森的解决方案。这是具有纳秒精度的clock_gettime() 的实现。

    //Import 
     #define _XOPEN_SOURCE 500
     #include <stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <time.h>
     #include <sys/time.h>
    
    
     int main(int argc, char *argv[])
     {   
         struct timespec ts;
         int ret;
         while(1)
         {
             ret = clock_gettime (CLOCK_MONOTONIC, &ts);
             if (ret) 
             {
                 perror ("clock_gettime");
                 return;
             }
             ts.tv_nsec += 20000; //goto sleep for 20000 n
             printf("Print before sleep tid%ld %ld\n",ts.tv_sec,ts.tv_nsec );
            // printf("going to sleep tid%d\n",turn );
             ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME,&ts, NULL);
    
         }
     }
    

    虽然很难达到 ns 精度,但这可用于在不到一微秒 (700-900 ns) 内获得精度。上面的 printf 用于打印线程#(打印一条语句肯定需要 2-3 微秒)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-28
      • 1970-01-01
      • 2020-10-19
      • 2018-04-06
      • 1970-01-01
      • 2010-12-28
      相关资源
      最近更新 更多