home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: alt.sources
- From: hakanson@CSE.OGI.EDU (Marion Hakanson)
- Subject: [comp.protocols.time.ntp] Unix clock resolution revisited
- Message-ID: <1990Sep14.173427.14607@math.lsa.umich.edu>
- Date: Fri, 14 Sep 90 17:34:27 GMT
-
- Archive-name: clockres/13-Sep-90
- Original-posting-by: hakanson@CSE.OGI.EDU (Marion Hakanson)
- Original-subject: Unix clock resolution revisited
- 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).]
-
- Well, I got tired of trying to convert microseconds into the power
- of two precision that ntpd and xntpd expect in their configuration
- files, so I added an option to my recently-posted clockres program
- to do the work for you.
-
- This program turns out to be more useful than I thought. On machines
- with clock resolutions better than clockres can measure (like the old
- SPARCstation-1), clockres ends up measuring the span of time between
- two gettimeofday(2) system calls. For consumption of any single
- threaded user program (like ntpd and xntpd), this turns out to be the
- perceived resolution of the clock, even if the underlying hardware
- clock is better. So the NTP precision value reported by clockres
- is probably a good value to tell ntpd or xntpd to advertise (and on
- most boxes, it agrees with the kernel hz value).
-
- More trivia: A friend tells me that a Convex C2 shows up with a
- resolution of 25 microseconds (again, this is the time between two
- system calls -- the underlying hardware clock is better). Who's next?
- Note that this is only three times better than a SPARC-1, but I hear
- you can do a lot more between system calls on a Convex.
-
- The program is included below. I'm still ambivalent about collecting
- results. While I'm curious about various machines (especially
- "exotic" boxes or those with exceptional results), I'm not anxious to
- have everyone who has a Sun workstation or a [34]86 box sending me
- their results. Certainly this program could be included with the
- other NTP programs in the FTP archives, as it may come in handy for
- those who have a lesser-known machine/OS, and it would save
- maintaining a database of reported results. Have at it, Louie.
-
- Hey, don't everybody run this at once -- you'll slow down the universe
- (especially if it runs SunOS :-).
-
- --
- Marion Hakanson Domain: hakanson@cse.ogi.edu
- UUCP : {hp-pcd,tektronix}!ogicse!hakanson
-
- ===============================================
- #ifndef lint
- char rcsid[] = "$Id: clockres.c,v 1.11 90/09/12 16:26:27 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 "-n" option
- * will convert the result to the NTP precision (power of two).
- *
- * 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[];
- {
- register int fakemicro;
- int ntpprecision;
- int verbose;
- int again;
- struct timeval t1, t2;
- register int calls;
- unsigned long diff, quotient;
- int power;
- int c;
-
-
- verbose = 0;
- fakemicro = 1;
- ntpprecision = 0;
-
- while ( (c = getopt(argc, argv, "fnv")) != EOF ) {
- switch ( c ) {
- case 'f':
- fakemicro = 0;
- break;
- case 'n':
- ntpprecision = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- case '?':
- fprintf(stderr, "usage: %s [-fnv]\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;
-
- diff = t2.tv_usec - t1.tv_usec;
-
- printf ("Clock step resolution %d microseconds", diff);
-
- if ( calls == 1 )
- printf (" or better");
-
- if ( ntpprecision ) {
- quotient = 1000000;
- power = 0;
-
- while ( quotient > diff ) {
- quotient >>= 1;
- --power;
- }
- printf (" (NTP precision %d)", power);
- }
-
- printf("\n");
-
- exit(0);
- }
- ===============================================
-