views:

886

answers:

5

Hi,

I'm using a open-source library for i2c bus actions. This library frequently uses a function to obtain an actual time-stamp with millisecond resolution.

Example Call:

nowtime = timer_nowtime();
while ((i2c_CheckBit(dev) == true) && ((timer_nowtime() - nowtime) < I2C_TIMEOUT));

The application using this i2c library uses a lot of CPU capacity. I figured out, that the running program the most time is calling the function timer_nowtime().

The original function:

unsigned long timer_nowtime(void) {        
    static bool usetimer = false;
    static unsigned long long inittime;
    struct tms cputime;

    if (usetimer == false)
    {
        inittime  = (unsigned long long)times(&cputime);
        usetimer = true;
    }

    return (unsigned long)((times(&cputime) - inittime)*1000UL/sysconf(_SC_CLK_TCK));
}

My aim now is, to improve the efficiency of this function. I tried it this way:

struct timespec systemtime;

clock_gettime(CLOCK_REALTIME, &systemtime);
//convert the to milliseconds timestamp
// incorrect way, because (1 / 1000000UL) always returns 0 -> thanks Pace
//return (unsigned long) ( (systemtime.tv_sec * 1000UL) + (systemtime.tv_nsec
//              * (1 / 1000000UL)));
return (unsigned long) ((systemtime.tv_sec * 1000UL)
            + (systemtime.tv_nsec / 1000000UL));

Unfortunately, I can't declare this function inline (no clue why).

Which way is more efficient to obtain an actual timestamp with ms resolution? I'm sure there is a more per-formant way to do so. Any suggestions?

thanks.

A: 

If your program only executes on recent Intel/AMD processors, but not too recent (clock throttling is not handled very well), the RDTSC assembly instruction is the best way to get a timestamp. The resolution is close to the actual clock of the processor and it is independent from the system (this means it is biased by interrupts, too. You can't have your cake and eat it too).

This page has an example in C.

Pascal Cuoq
rdtsc can also be problematic on multiprocessors, if your thread happens to switch to another core/hwthread, then the counter value will be nonsense, as they are not synchronized among cores. Hence it's almost always better to use the OS provided API's, in the case of POSIX clock_gettime().
janneb
RDTSC should not be used for timing purposes (not anymore..): http://en.wikipedia.org/wiki/Time_Stamp_Counter!
frunsi
I did say "not too recent" :)
Pascal Cuoq
Since the timerfunction is used to determine how much time passed by and the software is running on a single CPU embedded device, this solution would be an option. Of course this wouldn't be POSIX conform and hard to port onto another platform.
Maus
A: 

You could try the following code if you run on Intel

unsigned long long int rdtsc(void)
{
   unsigned long long int x;
   unsigned a, d;

   __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));

   return ((unsigned long long)a) | (((unsigned long long)d) << 32);;
}
Douglas Gemignani
I just noticed Pascal Cuoq already exposed the rdtsc instruction.
Douglas Gemignani
RDTSC should not be used for timing purposes (not anymore..): http://en.wikipedia.org/wiki/Time_Stamp_Counter!
frunsi
+3  A: 

Its clear that your example call uses most CPU time in timer_nowtime() function. You are polling, and the loop eats your CPU time. You could exchange the timer function with a better alternative and so you may achieve more loop iterations, but it will still use most CPU time in that function! You will not achieve using less CPU time by changing your timer function!

You may change your loop and introduce wait times - but only if it makes sense in your application, e.g.:

start = timer_nowtime();
while( i2c_CheckBit(dev) ) {
    now = timer_nowtime();
    diff = now - start;
    if( diff < I2C_TIMEOUT ) break;
    else if( diff > SOME_TRESHOLD ) usleep( 1000*std::max(1,I2C_TIMEOUT-diff-SOME_SMALL_NUMBER_1_TO_10_MAYBE) );
}

The timer: I think gettimeofday() would be a good decision, it has high precision and is available in most (all?) Unices.

frunsi
+2  A: 

Note that your two examples are not equivalent; times(2) measures CPU time consumptions, whereas clock_gettime(CLOCK_REALTIME, ...) measures the wallclock time.

That being said, wallclock timers such as clock_gettime or the older gettimeofday are usually much faster than CPU timers such as times() or getrusage().

And, as already noted, your timing function is using up much CPU time because you do little else than polling it. If that is a problem, wait a little bit e.g. by calling nanosleep() or clock_nanosleep().

I think your best option is to use clock_gettime(), however with CLOCK_MONOTONIC instead of CLOCK_REALTIME.

janneb
As these times are being used for bitbanging a hardware bus, wallclock time makes more sense than CPU time. So I agree with your CLOCK_MONOTONIC suggestion.
caf
+1  A: 

I have been happy with this on Linux:

inline double getFractionalSeconds(void) {
   struct timeval tv;   // see gettimeofday(2)
   gettimeofday(&tv, NULL);
   double t = (double) tv.tv_sec + (double) 1e-6 * tv.tv_usec; 
   // return seconds.microseconds since epoch 
   return(t);
}
Dirk Eddelbuettel