Annotation of embedaddon/ntp/util/precision.c, revision 1.1.1.1

1.1       misho       1: #include "ntp_unixtime.h"
                      2: 
                      3: #include <stdio.h>
                      4: 
                      5: #define        DEFAULT_SYS_PRECISION   -99
                      6: 
                      7: int default_get_resolution();
                      8: int default_get_precision();
                      9: 
                     10: int
                     11: main(
                     12:        int argc,
                     13:        char *argv[]
                     14:        )
                     15: {
                     16:        printf("log2(resolution) = %d, log2(precision) = %d\n",
                     17:               default_get_resolution(),
                     18:               default_get_precision());
                     19:        return 0;
                     20: }
                     21: 
                     22: /* Find the resolution of the system clock by watching how the current time
                     23:  * changes as we read it repeatedly.
                     24:  *
                     25:  * struct timeval is only good to 1us, which may cause problems as machines
                     26:  * get faster, but until then the logic goes:
                     27:  *
                     28:  * If a machine has resolution (i.e. accurate timing info) > 1us, then it will
                     29:  * probably use the "unused" low order bits as a counter (to force time to be
                     30:  * a strictly increaing variable), incrementing it each time any process
                     31:  * requests the time [[ or maybe time will stand still ? ]].
                     32:  *
                     33:  * SO: the logic goes:
                     34:  *
                     35:  *      IF      the difference from the last time is "small" (< MINSTEP)
                     36:  *      THEN    this machine is "counting" with the low order bits
                     37:  *      ELIF    this is not the first time round the loop
                     38:  *      THEN    this machine *WAS* counting, and has now stepped
                     39:  *      ELSE    this machine has resolution < time to read clock
                     40:  *
                     41:  * SO: if it exits on the first loop, assume "full accuracy" (1us)
                     42:  *     otherwise, take the log2(observered difference, rounded UP)
                     43:  *
                     44:  * MINLOOPS > 1 ensures that even if there is a STEP between the initial call
                     45:  * and the first loop, it doesn't stop too early.
                     46:  * Making it even greater allows MINSTEP to be reduced, assuming that the
                     47:  * chance of MINSTEP-1 other processes getting in and calling gettimeofday
                     48:  * between this processes's calls.
                     49:  * Reducing MINSTEP may be necessary as this sets an upper bound for the time
                     50:  * to actually call gettimeofday.
                     51:  */
                     52: 
                     53: #define        DUSECS  1000000
                     54: #define        HUSECS  (1024 * 1024)
                     55: #define        MINSTEP 5       /* some systems increment uS on each call */
                     56: /* Don't use "1" as some *other* process may read too*/
                     57: /*We assume no system actually *ANSWERS* in this time*/
                     58: #define MAXSTEP 20000   /* maximum clock increment (us) */
                     59: #define MINLOOPS 5      /* minimum number of step samples */
                     60: #define        MAXLOOPS HUSECS /* Assume precision < .1s ! */
                     61: 
                     62: int
                     63: default_get_resolution(void)
                     64: {
                     65:        struct timeval tp;
                     66:        struct timezone tzp;
                     67:        long last;
                     68:        int i;
                     69:        long diff;
                     70:        long val;
                     71:        int minsteps = MINLOOPS;        /* need at least this many steps */
                     72: 
                     73:        gettimeofday(&tp, &tzp);
                     74:        last = tp.tv_usec;
                     75:        for (i = - --minsteps; i< MAXLOOPS; i++) {
                     76:                gettimeofday(&tp, &tzp);
                     77:                diff = tp.tv_usec - last;
                     78:                if (diff < 0) diff += DUSECS;
                     79:                if (diff > MINSTEP) if (minsteps-- <= 0) break;
                     80:                last = tp.tv_usec;
                     81:        }
                     82: 
                     83:        printf("resolution = %ld usec after %d loop%s\n",
                     84:               diff, i, (i==1) ? "" : "s");
                     85: 
                     86:        diff = (diff *3)/2;
                     87:        if (i >= MAXLOOPS) {
                     88:                printf(
                     89:                        "     (Boy this machine is fast ! %d loops without a step)\n",
                     90:                        MAXLOOPS);
                     91:                diff = 1; /* No STEP, so FAST machine */
                     92:        }
                     93:        if (i == 0) {
                     94:                printf(
                     95:                        "     (The resolution is less than the time to read the clock -- Assume 1us)\n");
                     96:                diff = 1; /* time to read clock >= resolution */
                     97:        }
                     98:        for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i;
                     99:        printf("     (Oh dear -- that wasn't expected ! I'll guess !)\n");
                    100:        return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */;
                    101: }
                    102: 
                    103: /* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */
                    104: 
                    105: /*
                    106:  * This routine calculates the differences between successive calls to
                    107:  * gettimeofday(). If a difference is less than zero, the us field
                    108:  * has rolled over to the next second, so we add a second in us. If
                    109:  * the difference is greater than zero and less than MINSTEP, the
                    110:  * clock has been advanced by a small amount to avoid standing still.
                    111:  * If the clock has advanced by a greater amount, then a timer interrupt
                    112:  * has occurred and this amount represents the precision of the clock.
                    113:  * In order to guard against spurious values, which could occur if we
                    114:  * happen to hit a fat interrupt, we do this for MINLOOPS times and
                    115:  * keep the minimum value obtained.
                    116:  */  
                    117: int
                    118: default_get_precision(void)
                    119: {
                    120:        struct timeval tp;
                    121:        struct timezone tzp;
                    122: #ifdef HAVE_GETCLOCK
                    123:        struct timespec ts;
                    124: #endif
                    125:        long last;
                    126:        int i;
                    127:        long diff;
                    128:        long val;
                    129:        long usec;
                    130: 
                    131:        usec = 0;
                    132:        val = MAXSTEP;
                    133: #ifdef HAVE_GETCLOCK
                    134:        (void) getclock(TIMEOFDAY, &ts);
                    135:        tp.tv_sec = ts.tv_sec;
                    136:        tp.tv_usec = ts.tv_nsec / 1000;
                    137: #else /*  not HAVE_GETCLOCK */
                    138:        GETTIMEOFDAY(&tp, &tzp);
                    139: #endif /* not HAVE_GETCLOCK */
                    140:        last = tp.tv_usec;
                    141:        for (i = 0; i < MINLOOPS && usec < HUSECS;) {
                    142: #ifdef HAVE_GETCLOCK
                    143:                (void) getclock(TIMEOFDAY, &ts);
                    144:                tp.tv_sec = ts.tv_sec;
                    145:                tp.tv_usec = ts.tv_nsec / 1000;
                    146: #else /*  not HAVE_GETCLOCK */
                    147:                GETTIMEOFDAY(&tp, &tzp);
                    148: #endif /* not HAVE_GETCLOCK */
                    149:                diff = tp.tv_usec - last;
                    150:                last = tp.tv_usec;
                    151:                if (diff < 0)
                    152:                    diff += DUSECS;
                    153:                usec += diff;
                    154:                if (diff > MINSTEP) {
                    155:                        i++;
                    156:                        if (diff < val)
                    157:                            val = diff;
                    158:                }
                    159:        }
                    160:        printf("precision  = %ld usec after %d loop%s\n",
                    161:               val, i, (i == 1) ? "" : "s");
                    162:        if (usec >= HUSECS) {
                    163:                printf("     (Boy this machine is fast ! usec was %ld)\n",
                    164:                       usec);
                    165:                val = MINSTEP;  /* val <= MINSTEP; fast machine */
                    166:        }
                    167:        diff = HUSECS;
                    168:        for (i = 0; diff > val; i--)
                    169:            diff >>= 1;
                    170:        return (i);
                    171: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>