clock() precision in time.h

2019-01-18 13:59发布

问题:

I am trying to calculate the number of ticks a function uses to run and to do so an using the clock() function like so:

unsigned long time = clock();
myfunction();
unsigned long time2 = clock() - time;
printf("time elapsed : %lu",time2);

But the problem is that the value it returns is a multiple of 10000, which I think is the CLOCK_PER_SECOND. Is there a way or an equivalent function value that is more precise?

I am using Ubuntu 64-bit, but would prefer if the solution can work on other systems like Windows & Mac OS.

回答1:

There are a number of more accurate timers in POSIX.

  • gettimeofday() - officially obsolescent, but very widely available; microsecond resolution.
  • clock_gettime() - the replacement for gettimeofday() (but not necessarily so widely available; on an old version of Solaris, requires -lposix4 to link), with nanosecond resolution.

There are other sub-second timers of greater or lesser antiquity, portability, and resolution, including:

  • ftime() - millisecond resolution (marked 'legacy' in POSIX 2004; not in POSIX 2008).
  • clock() - which you already know about. Note that it measures CPU time, not elapsed (wall clock) time.
  • times() - CLK_TCK or HZ. Note that this measures CPU time for parent and child processes.

Do not use ftime() or times() unless there is nothing better. The ultimate fallback, but not meeting your immediate requirements, is

  • time() - one second resolution.

The clock() function reports in units of CLOCKS_PER_SEC, which is required to be 1,000,000 by POSIX, but the increment may happen less frequently (100 times per second was one common frequency). The return value must be defined by CLOCKS_PER_SEC to get time in seconds.



回答2:

Per the clock() manpage, on POSIX platforms the value of the CLOCKS_PER_SEC macro must be 1000000. As you say that the return value you're getting from clock() is a multiple of 10000, that would imply that the resolution is 10 ms.

Also note that clock() on Linux returns an approximation of the processor time used by the program. On Linux, again, scheduler statistics are updated when the scheduler runs, at CONFIG_HZ frequency. So if the periodic timer tick is 100 Hz, you get process CPU time consumption statistics with 10 ms resolution.

Walltime measurements are not bound by this, and can be much more accurate. clock_gettime(CLOCK_MONOTONIC, ...) on a modern Linux system provides nanosecond resolution.



回答3:

The most precise (but highly not portable) way to measure time is to count CPU ticks.

For instance on x86

 unsigned long long int asmx86Time ()
 {
   unsigned long long int realTimeClock = 0;
   asm volatile ( "rdtsc\n\t"         
                  "salq $32, %%rdx\n\t"    
                  "orq %%rdx, %%rax\n\t"   
                  "movq %%rax, %0"         
                  : "=r" ( realTimeClock ) 
                  : /* no inputs */
                  : "%rax", "%rdx" );
   return realTimeClock;
 }

 double cpuFreq ()
 {
   ifstream file ( "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" );
   string sFreq; if ( file ) file >> sFreq;
   stringstream ssFreq ( sFreq ); double freq = 0.;
   if ( ssFreq ) { ssFreq >> freq; freq *= 1000; } // kHz to Hz
   return freq;
 }

 // Timing

 unsigned long long int asmStart = asmx86Time ();
 doStuff ();
 unsigned long long int asmStop  = asmx86Time ();
 float asmDuration = ( asmStop - asmStart ) / cpuFreq ();

If you don't have an x86, you'll have to re-write the assembler code accordingly to your CPU. If you need maximum precision, that's unfortunatelly the only way to go... otherwise use clock_gettime().



回答4:

I agree with the solution of Jonathan. Here is the implementation of clock_gettime() with nanoseconds of precision.

//Import 
 #define _XOPEN_SOURCE 500
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
 #include <sys/time.h>


 int main(int argc, char *argv[])
 {   
     struct timespec ts;
     int ret;
     while(1)
     {
         ret = clock_gettime (CLOCK_MONOTONIC, &ts);
         if (ret) 
         {
             perror ("clock_gettime");
             return;
         }
         ts.tv_nsec += 20000; //goto sleep for 20000 n
         printf("Print before sleep tid%ld %ld\n",ts.tv_sec,ts.tv_nsec );
        // printf("going to sleep tid%d\n",turn );
         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME,&ts, NULL);

     }
 }

Although It's difficult to achieve ns precision, but this can be used to get precision for less than a microseconds (700-900 ns). printf above is used to just print the thread # (it'll definitely take 2-3 micro seconds to just print a statement).



标签: c linux time clock