【问题标题】:Measuring elapsed time in linux for a c program在linux中测量c程序的经过时间
【发布时间】:2013-01-18 22:06:50
【问题描述】:

我正在尝试在 Linux 中测量经过的时间。我的答案一直返回零,这对我来说毫无意义。以下是我在程序中测量时间的方式。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

main()
{
    double p16 = 1, pi = 0, precision = 1000;
    int k;
    unsigned long micros = 0;
    float millis = 0.0;
    clock_t start, end;
    start = clock();
    // This section calculates pi
    for(k = 0; k <= precision; k++)
    {
        pi += 1.0 / p16 * (4.0 / (8 * k + 1) - 2.0 / (8 * k + 4) - 1.0 / (8 * k + 5) - 1.0 / (8 * k + 6));
        p16 *= 16;
    }
    end = clock();
    micros = end - start;
    millis = micros / 1000;
    printf("%f\n", millis); //my time keeps being returned as 0

    printf("this value of pi is  : %f\n", pi);
}

【问题讨论】:

标签: c linux time


【解决方案1】:

您编写的代码存在两个问题。

  1. 根据man 3 clockclock()的分辨率以CLOCKS_PER_SEC每秒为增量。在最近的 Cygwin 系统上,它是 200。根据变量的名称,您预计该值为 1,000,000。

  2. 这一行:

    millis = micros / 1000;
    

    会将商计算为整数,因为两个操作数都是整数。浮点类型的提升发生在分配给millis 时,此时小数部分已被丢弃。

要使用clock() 计算经过的秒数,您需要执行以下操作:

clock_t start, end;
float seconds;
start = clock();
// Your code here:
end = clock();
seconds = end - start; // time difference is now a float
seconds /= CLOCKS_PER_SEC; // this division is now floating point

但是,您几乎肯定不会获得毫秒精度。为此,您需要使用gettimeofday()clock_gettime()。此外,您可能希望使用double 而不是float,因为您很可能会以非常小的差异减去非常大的数字。使用clock_gettime() 的示例是:

#include <time.h>
/* Floating point nanoseconds per second */
#define NANO_PER_SEC 1000000000.0

int main(void)
{
    struct timespec start, end;
    double start_sec, end_sec, elapsed_sec;
    clock_gettime(CLOCK_REALTIME, &start);
    // Your code here
    clock_gettime(CLOCK_REALTIME, &end);
    start_sec = start.tv_sec + start.tv_nsec / NANO_PER_SEC;
    end_sec = end.tv_sec + end.tv_nsec / NANO_PER_SEC;
    elapsed_sec = end_sec - start_sec;
    printf("The operation took %.3f seconds\n", elapsed_sec);

    return 0;
}

由于NANO_PER_SEC是一个浮点数,除法运算以浮点数进行。

来源:
clock(3)gettimeofday(3)clock_gettime(3) 的页面man
C 编程 语言,Kernighan 和 Ritchie

【讨论】:

  • end_sec = end.tv_sec + end.tv_n_sec/NANO_PER_SEC;将是:end_sec = end.tv_sec + end.tv_nsec / NANO_PER_SEC;
【解决方案2】:

三种选择

  1. clock()
  2. gettimeofday()
  3. clock_gettime()

clock_gettime() 达到纳秒精度,并支持 4 个时钟。

  • CLOCK_REALTIME

    系统范围的实时时钟。设置此时钟需要适当的权限。

  • CLOCK_MONOTONIC

    无法设置的时钟,表示自某个未指定起点以来的单调时间。

  • CLOCK_PROCESS_CPUTIME_ID

    来自 CPU 的高分辨率每进程计时器。

  • CLOCK_THREAD_CPUTIME_ID

    线程特定的 CPU 时间时钟。

你可以把它当作

#include <time.h>

struct timespec start, stop;

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);

/// do something

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);

double result = (stop.tv_sec - start.tv_sec) * 1e6 + (stop.tv_nsec - start.tv_nsec) / 1e3;    // in microseconds

【讨论】:

    【解决方案3】:

    当你除法时,你可能会得到一个小数,因此你需要一个浮点数来存储毫秒数。 如果不使用浮点数,小数部分将被截断。在您的代码中,开始和结束几乎相同。因此,以long存储时除法后的结果为“0”。

    unsigned long micros = 0;
    float millis = 0.0;
    clock_t start, end;
    
    start = clock();
    
    //code goes here
    
    end = clock();
    
    micros = end - start;
    millis = micros / 1000;
    

    【讨论】:

    • 尝试使用微秒。您的代码可能只需要很少的时间来执行,以便您在几秒钟内测量它。
    【解决方案4】:

    注意:clock() 函数返回进程的 CPU 时间,而不是挂钟时间。我相信这是 OP 感兴趣的。如果需要挂钟时间,那么 gettimeofday() 是一个不错的选择,正如先前答案所建议的那样。如果您的系统支持,clock_gettime() 可以做任何一个;在我的 linux 嵌入式系统上不支持clock_gettime(),但是clock() 和gettimeofday() 支持。

    下面是使用 gettimeofday() 获取挂钟时间的代码

    #include <stdio.h> // for printf()
    #include <sys/time.h> // for clock_gettime()
    #include <unistd.h> // for usleep()
    
    int main() {
        struct timeval start, end;
        long secs_used,micros_used;
    
        gettimeofday(&start, NULL);
        usleep(1250000); // Do the stuff you want to time here
        gettimeofday(&end, NULL);
    
        printf("start: %d secs, %d usecs\n",start.tv_sec,start.tv_usec);
        printf("end: %d secs, %d usecs\n",end.tv_sec,end.tv_usec);
    
        secs_used=(end.tv_sec - start.tv_sec); //avoid overflow by subtracting first
        micros_used= ((secs_used*1000000) + end.tv_usec) - (start.tv_usec);
    
        printf("micros_used: %d\n",micros_used);
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      尝试 Sunil D S 的答案,但将 micros 从 unsigned long 更改为 float 或 double 类型,如下所示:

      double micros;
      float seconds;
      
      clock_t start, end;
      
      start = clock();
      
      /* Do something here */
      
      end = clock();
      
      micros = end - start;
      seconds = micros / 1000000;
      

      或者,您可以使用 rusage,如下所示:

      struct rusage before;
      
      struct rusage after;
      
      float a_cputime, b_cputime, e_cputime;
      
      float a_systime, b_systime, e_systime;
      
      getrusage(RUSAGE_SELF, &before);
      
      /* Do something here! or put in loop and do many times */
      
      getrusage(RUSAGE_SELF, &after);
      
      a_cputime = after.ru_utime.tv_sec + after.ru_utime.tv_usec / 1000000.0;
      
      b_cputime = before.ru_utime.tv_sec + before.ru_utime.tv_usec / 1000000.0;
      
      e_cputime = a_cputime - b_cputime;
      
      a_systime = after.ru_stime.tv_sec + after.ru_stime.tv_usec / 1000000.0;
      
      b_systime = before.ru_stime.tv_sec + before.ru_stime.tv_usec / 1000000.0;
      
      e_systime = a_systime - b_systime;
      
      
      printf("CPU time (secs): user=%.4f; system=%.4f; real=%.4f\n",e_cputime, e_systime, seconds);
      

      单位和精度取决于您要测量多少时间,但其中任何一个都应该 为 ms 提供合理的准确性。

      【讨论】:

        【解决方案6】:

        首先,您需要使用浮点运算。任何整数值除以更大的整数值将始终为零。

        当然,您实际上应该在获取开始时间和结束时间之间一些事情。


        顺便说一句,如果您可以访问gettimeofday,它通常比clock 更受欢迎,因为它具有更高的分辨率。或者clock_gettime 的分辨率更高。

        【讨论】:

        • 谢谢。请问有gettimeofday的链接吗
        • @Jackwelch,没有理由不在 linux 上使用man 命令。
        • @Jackwelch 使用功能手册页的链接更新了答案。
        • 如果我可以问你一个简单的问题。你如何测量 linux 机器上的经过时间
        • @Jackwelch 就像您在问题中所做的那样。获取开始时间,做一些工作,获取结束时间,然后计算差值。所涉及的实际功能和结构并不重要。
        猜你喜欢
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-05
        • 2011-11-17
        相关资源
        最近更新 更多