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>