hakanson@CSE.OGI.EDU (Marion Hakanson) (08/16/90)
Archive-name: clockres/15-Aug-90 Original-posting-by: hakanson@CSE.OGI.EDU (Marion Hakanson) Original-subject: Unix system clock resolution (precision) Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti) [Reposted from comp.protocols.time.ntp. Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).] Below find clockres.c, source to a program which will tell you (most of the time) the resolution of your gettimeofday(2) system call, and thus probably the precision of your system's underlying clock. It has uses other than satisfying curiosity: you may be able to use it to tell an ntp server what precision to use, or to find out how accurate various performance measurements might be. Do keep in mind that ntpd's estimate using the kernel HZ value is probably best for most machines. Bug reports would be welcome to me, though it's pretty simple. I don't really care to create an archive of the results on various and sundry computer systems -- it takes less time to compile and run the program than it does to ftp a list from somewhere to look up your machine. But perhaps such an archive would be of use to prospective purchasers of hardware. I certainly ran into some surprises (like maybe 2^-6 isn't "bad" enough for an NTP precision). Here's a list of what I've encountered so far, in no particular order (the "or better" is explained in the program header commentary). ============= Hardware O/S software Resolution (microseconds) HP-9000/320 4.3bsd/Univ.Utah 336 or better (prob. 4) HP-9000/200 4.3bsd/Berkeley 830 or better (prob. 4) DEC-DS2100 Ultrix-3.1 (UWS-2.2) 3906 DEC-uVAX/II 4.3bsd/MtXinu 10000 Sun-4/60 SunOS-4.0.3c 53 or better (maybe 1?) Sun-4/60 SunOS-4.1(c) 62 or better (maybe 1?) Sun-4/65 SunOS-4.1(c) 10000 Sun-4/110 SunOS-4.0.3 10000 Sun-4/280 SunOS-4.0.3 10000 Sun-3/50 SunOS-4.0.3 20000 Sun-3/60 SunOS-4.1 20000 Sequent-S81 DYNIX-3.0.12 10000 Sequent-B21 DYNIX-3.1.alpha1 10000 Tek-431[57] UTek-3.1 50000 (missed the boat again) ============= ============= #ifndef lint char rcsid[] = "$Id: clockres.c,v 1.9 90/08/14 23:41:21 hakanson Exp $"; #endif /* lint */ /* * Determine the resolution of the system clock (gettimeofday(2)). * Marion Hakanson (hakanson@cse.ogi.edu) * Oregon Graduate Institute of Science and Technology * * The idea is to call gettimeofday(2), then repeatedly call it again * until you get a different value. The difference between the two * values should be the resolution (precision) of the system clock. * A little noise sometimes creeps in, due to adjtime(2)'s being done, * but in practice this appears rarely and can be factored out by running * this test program repeatedly (say 10 times). There is a "-v" option * to print out the two differing timestamps (and the number of calls * it took before a difference was detected). You may occasionally * see two (but never more) of these printed out before a result is * announced -- this is to avoid anomalies with comparing microseconds * when a wrap to the next full second has occurred. * * The big flaw to this approach is that most 4.3bsd-based systems have * in their kernels a microtime() routine which is supposed to return * the current time to the microsecond. A "good" implementation would * (e.g.) read a hardware interval timer to determine how many usec's * had passed since the last clock tick. But much hardware seems to * lack such a timer, and as a result, most implementations of microtime() * fake it by adding a microsecond to the current time for each subsequent * call to microtime() -- just to ensure that two invocations never return * exactly the same value (the fake microseconds go away at the next clock * tick) . Since most machines (known to mortals) these days cannot make * a system call in one microsecond, this program has a hack in it to * detect these "fake" microtime() implementations by adding the number * of gettimeofday(2) calls to the initial timestamp before comparing * with the most recent timestamp. A ">=" test is used to work with * older bsd's (like 4.2), where two subsequent timestamps often are * the same (within the value of a tick), and the "-f" option disables * the "fake" microtime() workaround. More irregular "fakes" will no * doubt be reported as terrific (but erroneous) clock resolutions. * * A small flaw is that if a machine has a clock resolution finer than * the time it takes to make a single pass through the loop, then the * program reports that value as the resolution of the clock, rather * than the actual resolution. A warning about this is printed when * a real difference is detected after only one pass (it says "... XX * microseconds or better" instead of just "... XX microseconds"). * Again, repeated runs can show this condition if the value seems to * fluctuate by a few microseconds and/or vary with system load (a * "genuine" result seems to stay rock solid across invocations). * In practice, few real machines seem to encounter this behavior, * and you should count yourself lucky if you have one. */ #include <stdio.h> #include <sys/time.h> extern int getopt(); main(argc, argv) int argc; char *argv[]; { int verbose; register int fakemicro; int again; struct timeval t1, t2; register int calls; int c; verbose = 0; fakemicro = 1; while ( (c = getopt(argc, argv, "fv")) != EOF ) { switch ( c ) { case 'f': fakemicro = 0; break; case 'v': verbose = 1; break; case '?': fprintf(stderr, "usage: %s [-fv]\n", argv[0]); exit(1); } } again = 0; top: if (again > 1) { fprintf (stderr, "%s: More than one second passed, giving up.\n", argv[0]); exit(1); } again++; calls = 0; (void) gettimeofday(&t1, NULL); do { calls++; (void) gettimeofday(&t2, NULL); } while ( (t1.tv_sec == t2.tv_sec) && ( fakemicro ? ((t1.tv_usec+calls) >= t2.tv_usec) : (t1.tv_usec == t2.tv_usec) ) ); if (verbose) { printf ("t1 %d.%06.6d t2 %d.%06.6d calls %d\n", t1.tv_sec, t1.tv_usec, t2.tv_sec, t2.tv_usec, calls); } /* Check for wrap to next second */ if (t1.tv_sec != t2.tv_sec) goto top; printf ("Clock step resolution %d microseconds", t2.tv_usec - t1.tv_usec); if ( calls == 1 ) printf (" or better"); printf("\n"); exit(0); } ============= -- Marion Hakanson Domain: hakanson@cse.ogi.edu UUCP : {hp-pcd,tektronix}!ogicse!hakanson