C中的最佳计时方法?

Posted

技术标签:

【中文标题】C中的最佳计时方法?【英文标题】:Best timing method in C? 【发布时间】:2010-10-02 08:40:32 【问题描述】:

对具有高分辨率和可移植性的代码段进行计时的最佳方法是什么?

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

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

是否有具有跨平台解决方案的标准库?

【问题讨论】:

【参考方案1】:

我认为这应该可行:

#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);

【讨论】:

这实际上很好,因为它为您提供 CPU 时间而不是经过的时间(经过的时间可能会受到其他进程的影响)。请记住,10 秒的数字并不一定意味着它将在 10 秒内运行,因为可能需要考虑 I/O。这测量 CPU。 我用了数百次,是这个问题最好/最简单的解决方案 如果您经常为多个事情计时,您甚至可以将所有这些内容放入一个宏中:#define timing(a) start=clock();一种;差异 = 时钟() - 开始;毫秒 = 差异 * 1000 / CLOCKS_PER_SEC; printf("毫秒: %d\n",msec);然后调用:timing(IntenseFunc1()) clock_t 通常是 long 而 CLOCKS_PER_SEC 是 1000000。在这种情况下,超过 4 秒的差异会给你溢出和奇怪的结果 @paxdiablo 我得到了与 gettimeofday() 完全一样的结果,不知道你在说什么。【参考方案2】:

gettimeofday() 可能会做你想做的事。

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

请注意,这是 CPU 周期数。在 linux 上,您可以从 /proc/cpuinfo 获取 CPU 速度,然后除以获取秒数。将其转换为双精度非常方便。

当我在我的盒子上运行它时,我得到了

11867927879484732 11867927879692217 调用 printf 花了这么长时间:207485

Intel developer's guide 提供了大量细节。

#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);

【讨论】:

【参考方案3】:

gettimeofday 将在系统时钟的分辨率内返回精确到微秒的时间。您可能还想查看 SourceForge 上的 High Res Timers 项目。

【讨论】:

【参考方案4】:

我使用来自SDL library 的SDL_GetTicks。

【讨论】:

【参考方案5】:

如果您不想要 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);                                                                                                                                                           

【讨论】:

【参考方案6】:

高分辨率是相对的... 我正在查看示例,它们主要满足毫秒级的需求。 但是对我来说,测量微秒很重要。 我还没有看到微秒级独立于平台的解决方案,我认为下面的代码会很有用。 我暂时只在 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

【讨论】:

以上是关于C中的最佳计时方法?的主要内容,如果未能解决你的问题,请参考以下文章

保存计时器集合的最佳方法(对象与指针)

Linux之C++毫秒级计时方法

C中的计时函数[重复]

.NET 中的精确计时

在另一个线程中独立计时 For 循环的每个滴答声的最佳方法

在 Windows 服务中使用的最佳计时器