在C语言中,最佳的计时方法是什么?

90

如何以高分辨率和可移植性计时代码部分的最佳方法是什么?

/* Time from here */
ProcessIntenseFunction();
/* to here. */

printf("Time taken %d seconds %d milliseconds", sec, msec);

是否有一个标准库可以提供跨平台的解决方案?

6个回答

153

我认为这应该可以工作:

#include <time.h>

clock_t start = clock(), diff;
ProcessIntenseFunction();
diff = clock() - start;

int msec = diff * 1000 / CLOCKS_PER_SEC;
printf("Time taken %d seconds %d milliseconds", msec/1000, msec%1000);

14
这实际上很好,因为它给你CPU时间而不是经过的时间(经过的时间可能会受其他进程的影响)。只需记住,10秒钟的数字并不一定意味着它将在10秒钟内运行,因为可能存在I/O考虑因素。这只测量CPU时间。 - paxdiablo
2
我已经使用了数百次,这是此问题的最佳/最简单的解决方案。 - Gerhard
6
如果您需要经常计时多个事物,甚至可以将所有内容都放入宏中:#define timing(a) start=clock(); a; diff = clock() - start; msec = diff * 1000 / CLOCKS_PER_SEC; printf("msecs: %d\n",msec);然后调用: timing(IntenseFunc1()) - eqzx
4
clock_t通常是长整型,而CLOCKS_PER_SEC是1000000。在这种情况下,超过4秒的差值将导致溢出和奇怪的结果。 - Begelfor
2
@paxdiablo,我使用这个函数得到的结果与gettimeofday()完全相同,不确定你在这里想表达什么。 - user3467349
显示剩余4条评论

24

gettimeofday()可能会满足您的需求。

如果您使用英特尔硬件,以下是如何读取CPU实时指令计数器的方法。它将告诉您自处理器启动以来执行的CPU周期数。这可能是您可以用于性能测量的最细粒度、开销最低的计数器。

请注意,这是CPU周期数。在Linux上,您可以从/proc/cpuinfo中获取CPU速度,并进行除法运算以获取秒数。将其转换为double非常方便。

当我在我的计算机上运行此代码时,我得到:

11867927879484732
11867927879692217
调用printf所需的时间:207485

这里是提供了大量细节的英特尔开发人员指南

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}

6

gettimeofday函数将返回精确到微秒的时间,但受系统时钟分辨率的限制。您也可以查看SourceForge上的High Res Timers项目。


2
如果您不需要CPU时间,那么我认为您需要的是timeval结构体。
我使用以下内容来计算执行时间:
int timeval_subtract(struct timeval *result,                                                                                                                                        
                     struct timeval end,                                                                                                                                                 
                     struct timeval start)                                                                                                                                               
{                                                                                                                                                                                   
        if (start.tv_usec < end.tv_usec) {                                                                                                                                          
                int nsec = (end.tv_usec - start.tv_usec) / 1000000 + 1;                                                                                                             
                end.tv_usec -= 1000000 * nsec;                                                                                                                                      
                end.tv_sec += nsec;                                                                                                                                                 
        }                                                                                                                                                                           
        if (start.tv_usec - end.tv_usec > 1000000) {                                                                                                                                
                int nsec = (end.tv_usec - start.tv_usec) / 1000000;                                                                                                                 
                end.tv_usec += 1000000 * nsec;                                                                                                                                      
                end.tv_sec -= nsec;                                                                                                                                                 
        }                                                                                                                                                                           

        result->tv_sec = end.tv_sec - start.tv_sec;                                                                                                                                 
        result->tv_usec = end.tv_usec - start.tv_usec;                                                                                                                              

        return end.tv_sec < start.tv_sec;                                                                                                                                           
}                                                                                                                                                                                   

void set_exec_time(int end)                                                                                                                                                         
{                                                                                                                                                                                   
        static struct timeval time_start;                                                                                                                                           
        struct timeval time_end;                                                                                                                                                    
        struct timeval time_diff;                                                                                                                                                   

        if (end) {                                                                                                                                                                  
                gettimeofday(&time_end, NULL);                                                                                                                                      
                if (timeval_subtract(&time_diff, time_end, time_start) == 0) {                                                                                                      
                        if (end == 1)                                                                                                                                               
                                printf("\nexec time: %1.2fs\n",                                                                                                                     
                                        time_diff.tv_sec + (time_diff.tv_usec / 1000000.0f));                                                                                       
                        else if (end == 2)                                                                                                                                          
                                printf("%1.2fs",                                                                                                                                    
                                        time_diff.tv_sec + (time_diff.tv_usec / 1000000.0f));                                                                                       
                }                                                                                                                                                                   
                return;                                                                                                                                                             
        }                                                                                                                                                                           
        gettimeofday(&time_start, NULL);                                                                                                                                            
}                                                                                                                                                                                   

void start_exec_timer()                                                                                                                                                             
{                                                                                                                                                                                   
        set_exec_time(0);                                                                                                                                                           
}                                                                                                                                                                                   

void print_exec_timer()                                                                                                                                                             
{                                                                                                                                                                                   
        set_exec_time(1);                                                                                                                                                           
}

1

0

高分辨率是相对的... 我看了一些例子,它们大多数都是以毫秒为单位的。 然而,对我来说,测量微秒很重要。 我还没有看到一个平台无关的微秒解决方案,所以认为像下面的代码将会很有用。 目前我只在Windows上进行计时,当在AIX/Linux上进行相同操作时,很可能会添加一个gettimeofday()实现。

    #ifdef WIN32
      #ifndef PERFTIME
        #include <windows.h>
        #include <winbase.h>
        #define PERFTIME_INIT unsigned __int64 freq;  QueryPerformanceFrequency((LARGE_INTEGER*)&freq); double timerFrequency = (1.0/freq);  unsigned __int64 startTime;  unsigned __int64 endTime;  double timeDifferenceInMilliseconds;
        #define PERFTIME_START QueryPerformanceCounter((LARGE_INTEGER *)&startTime);
        #define PERFTIME_END QueryPerformanceCounter((LARGE_INTEGER *)&endTime); timeDifferenceInMilliseconds = ((endTime-startTime) * timerFrequency);  printf("Timing %fms\n",timeDifferenceInMilliseconds);
    #define PERFTIME(funct) {unsigned __int64 freq;  QueryPerformanceFrequency((LARGE_INTEGER*)&freq);  double timerFrequency = (1.0/freq);  unsigned __int64 startTime;  QueryPerformanceCounter((LARGE_INTEGER *)&startTime);  unsigned __int64 endTime;  funct; QueryPerformanceCounter((LARGE_INTEGER *)&endTime);  double timeDifferenceInMilliseconds = ((endTime-startTime) * timerFrequency);  printf("Timing %fms\n",timeDifferenceInMilliseconds);}
      #endif
    #else
      //AIX/Linux gettimeofday() implementation here
    #endif

使用方法:

PERFTIME(ProcessIntenseFunction());

or

PERFTIME_INIT
PERFTIME_START
ProcessIntenseFunction()
PERFTIME_END

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