Change the default for ntpd back to -s, the bug which triggered this
[dragonfly.git] / contrib / ntp / util / precision.c
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 }