Annotation of embedaddon/ntp/util/precision.c, revision 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>