Subject: clock precision

From: Oleg Goldshmidt <[email-masked]>
Date: 14 Mar 2001 21:53:32 +0200

Hi,

Can anyone explain what the limits are on the precision of the
computer clock that I can get on an Intel PC? For instance, Linux (and
other BSD-like systems) boast a gettimeofday(2) function that yields
microseconds. I am told, without specifics, that NT has some kind of
clock function (what is it, anyone?) that has an even higher
precision.

On the other hand, the Linux RTC Clock documentation
(Documentation/rtc.txt in your kernel) talks about a 8192 Hz clock
only (122 us), which seems to be a hardware limit. Yes, CPU speeds are
in GHz (ns) now, and maybe one can get a timer out of that (can
one?). Will it really have a ns precision though? Does gettimeofday(2)
on a PC really provide a us precision?

Asking the question differently, can I get a timestamp on an Intel PC
(with NT or Linux) that will really give me precision higher than 122
us? If yes, could you offer pointers?

Is the answer so obvious that I've just made a fool of myself? ;-)

Thanks,

-- 
Oleg Goldshmidt | [email-masked] 
"... We work by wit, and not by witchcraft;
 And wit depends on dilatory time." [Shakespeare]

---

From: Omer Mussaev <[email-masked]>
Date: Thu, 15 Mar 2001 17:13:28 +0200

> Is the answer so obvious that I've just made a fool of myself? ;-)

The answer is not so obvous.
gettimeofday and settimofday operate on timeval structure, which can not 
hold
values with resulution higher than 1 usec (microsecond).

However, that does not mean that you actually can get usec precision 
with those
functions. Actually, while on Solaris on SPARC you do get precision 
close to
usecs, on Linux/i386 the best values are measured by milliseconds ( 1000 
* usec ).

Having said that, you have to consider yet another complication: latency.
On my machine (550 MHz Pentium III running RH6.1 + linux 2.2.x ) ,
gettimeofday took somewhere between  3833 to  5585 CPU cycles to complete
when CPU cache is cold (not holding values from previous run) and  467[+-1]
cycles when cache is warm. That is pretty good performance, of course, 
but it
is not always appropriate for real-time applications.

When you approach RT (or something close to, like networking subsystems 
in my
case), you may need something faster/more precise.

On intel P6 architecture and later there is TSC register which can be 
used for very
precise timing:

here is usage example from user-space:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <asm/msr.h>

#define KB 1024
#define MB ( 1024 * 1024 )
int main( int argc, char *argv[] )
{ 
  long long tsc1, tsc2 ;
  int a, b = 100 ;
  float c, d = 1.0 ;
  struct stat sb ;
  char *ptr ;
   
  rdtscll( tsc1 ) ;
  a = b ;
  rdtscll( tsc2 ) ;
  printf( "int assign: \t%lld cycles\n", tsc2-tsc1 ) ;

  rdtscll( tsc1 ) ;
  c = d ;
  rdtscll( tsc2 ) ;
  printf( "float assign: \t%lld cycles\n", tsc2-tsc1 ) ;

  rdtscll( tsc1 ) ;
  a * b ;
  rdtscll( tsc2 ) ;
  printf( "integer mult: \t%lld cycles\n", tsc2-tsc1 ) ;

  rdtscll( tsc1 ) ;
  c * d ;
  rdtscll( tsc2 ) ;
  printf( "float mult: \t%lld cycles\n", tsc2-tsc1 ) ;

  rdtscll( tsc1 ) ;
  stat( "/", &sb ) ;
  rdtscll( tsc2 ) ;
  printf( "stat:      \t%lld cycles\n", tsc2-tsc1 ) ;

  rdtscll( tsc1 ) ;
  ptr = malloc( 1 * KB ) ;
  rdtscll( tsc2 ) ;
  printf( "malloc 1 KB: \t%lld cycles\n", tsc2-tsc1 ) ;
  free( ptr );
 
  rdtscll( tsc1 ) ;
  ptr = malloc( 1 * MB ) ;
  rdtscll( tsc2 ) ;
  printf( "malloc 1 MB: \t%lld cycles\n", tsc2-tsc1 ) ;
  free( ptr );
}

here is output on my machine:

rage-[17:12:03]-( <none> )-/users/omerm$./a.out
int assign:     36 cycles
float assign:     639 cycles
integer mult:     32 cycles
float mult:     32 cycles
stat:          6062 cycles
malloc 1 KB:     21184 cycles
malloc 1 MB:     9886 cycles
rage-[17:12:58]-( <none> )-/users/omerm$

Regards,

 -- 
--   
Omer Mussaev 054308250 mailto:[email-masked]
  Mercury Interactive / APM core technologies R&D