【问题标题】:Strange clock() behaviour奇怪的时钟()行为
【发布时间】:2016-06-16 12:05:36
【问题描述】:

有人可以解释一下这个 clock() (time_h) 的行为吗:

clock_t start, stop;
long i;
double t = 0.;
for(i = 0; i < 10e7; i++){
    start = clock();
    //nothing
    stop = clock();
    t = t + (double)(stop - start) / CLOCKS_PER_SEC;
}
printf("t: %fs\n", t);

输出:

t: 12.883712s

我认为原因可能是由clock() 错误引起的小t 值的累积。有办法解决吗?

更新:只是为了解释“现实世界”的情况,因为有很多建议。 //nothing 是一段代码,其时间间隔非常小(可能是纳米级),而不是一个循环,其中很少有也很难测量。

【问题讨论】:

  • 你为什么期望 start 和 stop 是相等的?调用“clock()”并将值复制到变量不是“//nothing”;)
  • 执行你的程序需要多长时间(使用真正的挂钟)?
  • 期望值是多少?当然不是零,两次测量之间时钟上升的概率非零。
  • #include &lt;time.h&gt; 在哪里?否则,clock() 的返回值将被截断为有符号的int 值。
  • @Matsmath clock() 执行会影响总时间,因此没有必要测量程序总时间。

标签: c time clock


【解决方案1】:

您得到的答案是合理的,因为编译器无法优化 clock() 调用,而且我不认为对 clock() 的调用特别便宜。

但是您的测量在数值上不准确 - 我认为您的方法低估了总数。试试

clock_t start, stop;
clock_t total = 0;
for (long/*don't overflow a 16 bit int*/ i = 0; i < 10e7; i++){
    start = clock();
    stop = clock();
    total += stop - start
}
double t = 1.0 * total / CLOCKS_PER_SEC;
printf("t: %fs\n", t);

相反。即在最后进行除法。

在某种意义上,您可以校准使用

start = clock();
/*ToDo - the real code*/
stop = clock();
control = clock();
/*Time is (stop - start) - (control - stop)*/

【讨论】:

  • 你做了一些有价值的标记,但结果还是一样。
  • 校准 可能是一个很好的技巧,但仍然存在小时间间隔不准确的问题。 clock_gettime() 可以用它的纳米精度处理它的模拟人生。
  • 注意:i &lt; 10e7 会生成 FP 代码。建议i &lt; (long)10e7。可能不会改变输出,但会运行得更快/一样快。
【解决方案2】:

您无法使用 clock() 测量非常短的时间跨度(或者就此而言,使用任何其他方法,除非您使用实时操作系统并非常小心)。

将很多小的测量值加起来并不是一个好主意,因为粒度问题可能会累积。测量大循环并除以迭代次数要好得多:

clock_t start, stop;
long i, num_iter = 1e8;
start = clock();
for(i = 0; i < num_iter; i++){
    //whatever
}
stop = clock();
t = (double)(stop - start) / num_iter / CLOCKS_PER_SEC;
printf("t: %fs\n", t);

如果你觉得//whatever的时间太短,就增加迭代次数吧!

但是如果循环代码有两个部分:一个是准备数据,另一个是你想要测量的真实代码呢? ...如果没有准备阶段,您将无法运行真正的代码。或者简单地说,如果我要测量的代码很短并且循环开销太大怎么办?

那么一种方法是运行两次测量,其中一次绕过待测量代码,然后计算差异:

clock_t start, time1, time2;
long i, num_iter = 1e8;
double t;

start = clock();
for(i = 0; i < num_iter; i++){
    prepare_algoritm();
}
time1 = clock() - start;

start = clock();
for(i = 0; i < num_iter; i++){
    prepare_algoritm();
    run_algorith();
}
time2 = clock() - start;

t = (double)(time2 - time1) / num_iter / CLOCKS_PER_SEC; 
printf("run_algorithm time: %fs\n", t);

【讨论】:

    【解决方案3】:

    考虑对您的程序进行以下修改:

    #include <time.h>
    #include <stdio.h>
    
    int main( int argc, char *argv[]) {
      clock_t start, stop;
      int i;
      double t = 0.;
      int n = atoi(argv[1]);
      int cnt = 0;
      for(i = 0; i < n; i++){
        start = clock();
        //nothing
        stop = clock();
        if ( start != stop) {
          printf( "%d %d\n", start, stop);
          cnt++;
        }
        t = t + (double)(stop - start) / CLOCKS_PER_SEC;
      }
      printf("t: %gs %g %d\n", t, t/n, cnt);
      return 0;
    }
    

    两次运行的输出

    $ ./a.out 1000000
    30000 40000
    70000 80000
    90000 100000
    110000 120000
    170000 180000
    180000 190000
    220000 230000
    230000 240000
    240000 250000
    250000 260000
    260000 270000
    270000 280000
    t: 0.12s 1.2e-07 12
    
    $ ./a.out 100000
    t: 0s 0 0
    

    这表明您获得了非零值,因为当您运行循环足够多次时,startend 值是不同的,因为偶尔会在 clock 时间即将改变之前运行,因此第二次调用返回不同的值。当这种情况发生时,t 会增加。

    【讨论】:

    • 谢谢。因此,那些非零值足够不同,以至于它会在这个比例上产生巨大的误差(例如 10e7 为 12 秒)。这是你的意思吗?
    • @zarko 是的,stop - start 的差值为 10000,除以 CLOCKS_PER_SEC 时,变为 0.01。请注意,在上面的示例中,有 12 次 stopstart 不相等,测量时间为 0.12 (12*0.01)。它要么需要测量循环前后的时间,要么使用比clock()更准确的时间,也许clock_gettime()
    • 看来clock_gettime() 提供了纳秒级的分辨率。我会试试看。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多