C 语言中的最佳计时方法? ?

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

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


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

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

113102 次浏览

I think this should work:

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

gettimeofday will return time accurate to microseconds within the resolution of the system clock. You might also want to check out the High Res Timers project on SourceForge.

gettimeofday() will probably do what you want.

If you're on Intel hardware, here's how to read the CPU real-time instruction counter. It will tell you the number of CPU cycles executed since the processor was booted. This is probably the finest-grained, lowest overhead counter you can get for performance measurement.

Note that this is the number of CPU cycles. On linux you can get the CPU speed from /proc/cpuinfo and divide to get the number of seconds. Converting this to a double is quite handy.

When I run this on my box, I get

11867927879484732
11867927879692217
it took this long to call printf: 207485

Here's the Intel developer's guide that gives tons of detail.

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

High resolution is relative... I was looking at the examples and they mostly cater for milliseconds. However for me it is important to measure microseconds. I have not seen a platform independant solution for microseconds and thought something like the code below will be usefull. I was timing on windows only for the time being and will most likely add a gettimeofday() implementation when doing the same on AIX/Linux.

    #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

Usage:

PERFTIME(ProcessIntenseFunction());


or


PERFTIME_INIT
PERFTIME_START
ProcessIntenseFunction()
PERFTIME_END

If you don't want CPU time then I think what you're looking for is the timeval struct.

I use the below for calculating execution time:

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