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>