2 * Copyright the NTPsec project contributors
3 * SPDX-License-Identifier: BSD-2-Clause
11 #include "ntp_types.h"
12 #include "ntp_calendar.h"
15 #define DEFAULT_SYS_PRECISION -99
17 int default_get_resolution(void);
18 int default_get_precision(void);
20 void precision(const iomode mode
)
23 printf("{\"log2 of resolution\":%d, \"log2 of precision\":%d}\n",
24 default_get_resolution(),
25 default_get_precision());
27 printf("log2(resolution) = %d, log2(precision) = %d\n",
28 default_get_resolution(),
29 default_get_precision());
33 /* Find the resolution of the system clock by watching how the current time
34 * changes as we read it repeatedly.
36 * If a machine has resolution (i.e. accurate timing info) > 1us, then it will
37 * probably use the "unused" low order bits as a counter (to force time to be
38 * a strictly increaing variable), incrementing it each time any process
39 * requests the time [[ or maybe time will stand still ? ]].
43 * IF the difference from the last time is "small" (< MINSTEP)
44 * THEN this machine is "counting" with the low order bits
45 * ELIF this is not the first time round the loop
46 * THEN this machine *WAS* counting, and has now stepped
47 * ELSE this machine has resolution < time to read clock
49 * SO: if it exits on the first loop, assume "full accuracy" (1us)
50 * otherwise, take the log2(observed difference, rounded UP)
52 * MINLOOPS > 1 ensures that even if there is a STEP between the initial call
53 * and the first loop, it doesn't stop too early.
54 * Making it even greater allows MINSTEP to be reduced, assuming that the
55 * chance of MINSTEP-1 other processes getting in and calling clock_gettime()
56 * between this processes's calls.
57 * Reducing MINSTEP may be necessary as this sets an upper bound for the time
58 * to actually call clock_gettime().
61 #define DNSECS 1000000000L
62 #define HUSECS (1024 * 1024)
63 #define MINSTEP 200 /* assume no system returns less than 200 nansec */
64 /* Don't use "1" as some *other* process may read too */
65 /* We assume no system actually *ANSWERS* in this time */
66 #define MAXSTEP 20000000 /* maximum clock increment (ns) */
67 #define MINLOOPS 5 /* minimum number of step samples */
68 #define MAXLOOPS (HUSECS * 1024) /* Assume precision < .1s ! */
71 default_get_resolution(void)
73 struct timespec tp
= {0, 0};
78 int minsteps
= MINLOOPS
; /* need at least this many steps */
80 clock_gettime(CLOCK_REALTIME
, &tp
);
82 for (i
= - --minsteps
; i
< MAXLOOPS
; i
++) {
83 clock_gettime(CLOCK_REALTIME
, &tp
);
84 diff
= tp
.tv_nsec
- last
;
85 if (diff
< 0) { diff
+= DNSECS
;
87 if (diff
> MINSTEP
&& minsteps
-- <= 0) {
92 diff
/= 1000; /* step down to milliseconds */
94 fprintf(stderr
, "resolution = %ld usec after %d loop%s\n",
95 diff
, i
, (i
==1) ? "" : "s");
100 " (Boy this machine is fast ! %d loops without a step)\n",
102 diff
= 1; /* No STEP, so FAST machine */
106 " (The resolution is less than the time to read the clock -- Assume 1us)\n");
107 diff
= 1; /* time to read clock >= resolution */
109 for (i
=0, val
=HUSECS
; val
>0; i
--, val
>>= 1) { if (diff
>= val
) {
114 " (Oh dear -- that wasn't expected ! I'll guess !)\n");
115 return DEFAULT_SYS_PRECISION
/* Something's BUST, so lie ! */;
118 /* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */
121 * This routine calculates the differences between successive calls to
122 * clock_gettime(REALTIME). If a difference is less than zero, the ns field
123 * has rolled over to the next second, so we add a second in ns. If
124 * the difference is greater than zero and less than MINSTEP, the
125 * clock has been advanced by a small amount to avoid standing still.
126 * If the clock has advanced by a greater amount, then a timer interrupt
127 * has occurred and this amount represents the precision of the clock.
128 * In order to guard against spurious values, which could occur if we
129 * happen to hit a fat interrupt, we do this for MINLOOPS times and
130 * keep the minimum value obtained.
133 default_get_precision(void)
135 struct timespec tp
= {0, 0};
144 clock_gettime(CLOCK_REALTIME
, &tp
);
146 for (i
= 0; i
< MINLOOPS
&& nsec
< HUSECS
* 1024;) {
147 clock_gettime(CLOCK_REALTIME
, &tp
);
148 diff
= tp
.tv_nsec
- last
;
154 if (diff
> MINSTEP
) {
161 val
/= 1000; /* step down to milliseconds */
162 fprintf(stderr
, "precision = %ld usec after %d loop%s\n",
163 val
, i
, (i
== 1) ? "" : "s");
164 if (nsec
>= HUSECS
* 1024) {
165 fprintf(stderr
, " (Boy this machine is fast! nsec was %ld)\n",
167 val
= MINSTEP
; /* val <= MINSTEP; fast machine */
170 for (i
= 0; diff
> val
; i
--) {