在Linux中为C程序测量经过的时间

6
我正在尝试在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);
}

我猜你的意思是代码在 clock() 调用之间。 - UmNyobe
请参阅以下链接以获取有关编程的信息:http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html - Rachel Gallen
@UmNyoben,我刚刚更新了代码以显示其中的内容。我遇到的问题是时间一直返回为0。 - Jack welch
GNU的time程序怎么样?或者,另外一个选择是Bash命令time - Andreas Grapentin
6个回答

22

三种选择

  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

8
注意: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;
}

4

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

当然,在获取开始和结束时间之间,您应该实际上 执行 一些操作。


顺便说一下,如果您可以访问 gettimeofday,通常优先于 clock,因为它具有更高的分辨率。或者也可以使用具有更高分辨率的clock_gettime


7
@Jackwelch,在Linux上使用“man”命令没有任何借口。 - Jens Gustedt
@Jackwelch 像你在问题中所做的那样。获取开始时间,进行一些工作,获取结束时间,并计算差异。实际涉及的函数和结构并不重要。 - Some programmer dude
@JoachimPileborg 还是不起作用。我刚刚更新了我的代码。时间仍然返回为0。 - Jack welch
@Jackwelch 你还在使用整数除法!改为 millis = micros / 1000.0f; - Some programmer dude
@BrianTiffin time 是指函数还是 shell 命令?如果是前者,它的精度较低;如果是后者,则仅适用于在 shell 中运行整个程序,而不适用于程序的某一部分。 - Some programmer dude
显示剩余5条评论

2
你的代码有两个问题。
  1. According to man 3 clock, the resolution of clock() is in CLOCKS_PER_SEC increments per second. On a recent-ish Cygwin system, it's 200. Based on the names of your variables, you are expecting the value to be 1,000,000.

  2. This line:

    millis = micros / 1000;
    

    will compute the quotient as an integer, because both operands are integers. The promotion to a floating-point type occurs at the time of the assignment to millis, at which point the fractional part has already been discarded.

为了使用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_nsec / NANO_PER_SEC; 可以这样写: - Jorge Matricali

1
当你进行除法运算时,可能会得到一个小数,因此你需要使用浮点数来存储毫秒数。如果不使用浮点数,小数部分将被截断。在你的代码片段中,开始和结束几乎相同。因此,当除法结果存储在 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;

尝试使用微秒。你的代码可能只需要很少的时间才能执行,以至于用秒来衡量它可能不够准确。 - Sunil D S

1
尝试使用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);

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接