1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
#include "ntp_unixtime.h"
#include <stdio.h>
#define DEFAULT_SYS_PRECISION -99
int default_get_resolution();
int default_get_precision();
int
main(
int argc,
char *argv[]
)
{
printf("log2(resolution) = %d, log2(precision) = %d\n",
default_get_resolution(),
default_get_precision());
return 0;
}
/* Find the resolution of the system clock by watching how the current time
* changes as we read it repeatedly.
*
* struct timeval is only good to 1us, which may cause problems as machines
* get faster, but until then the logic goes:
*
* If a machine has resolution (i.e. accurate timing info) > 1us, then it will
* probably use the "unused" low order bits as a counter (to force time to be
* a strictly increaing variable), incrementing it each time any process
* requests the time [[ or maybe time will stand still ? ]].
*
* SO: the logic goes:
*
* IF the difference from the last time is "small" (< MINSTEP)
* THEN this machine is "counting" with the low order bits
* ELIF this is not the first time round the loop
* THEN this machine *WAS* counting, and has now stepped
* ELSE this machine has resolution < time to read clock
*
* SO: if it exits on the first loop, assume "full accuracy" (1us)
* otherwise, take the log2(observered difference, rounded UP)
*
* MINLOOPS > 1 ensures that even if there is a STEP between the initial call
* and the first loop, it doesn't stop too early.
* Making it even greater allows MINSTEP to be reduced, assuming that the
* chance of MINSTEP-1 other processes getting in and calling gettimeofday
* between this processes's calls.
* Reducing MINSTEP may be necessary as this sets an upper bound for the time
* to actually call gettimeofday.
*/
#define DUSECS 1000000
#define HUSECS (1024 * 1024)
#define MINSTEP 5 /* some systems increment uS on each call */
/* Don't use "1" as some *other* process may read too*/
/*We assume no system actually *ANSWERS* in this time*/
#define MAXSTEP 20000 /* maximum clock increment (us) */
#define MINLOOPS 5 /* minimum number of step samples */
#define MAXLOOPS HUSECS /* Assume precision < .1s ! */
int
default_get_resolution(void)
{
struct timeval tp;
struct timezone tzp;
long last;
int i;
long diff;
long val;
int minsteps = MINLOOPS; /* need at least this many steps */
gettimeofday(&tp, &tzp);
last = tp.tv_usec;
for (i = - --minsteps; i< MAXLOOPS; i++) {
gettimeofday(&tp, &tzp);
diff = tp.tv_usec - last;
if (diff < 0) diff += DUSECS;
if (diff > MINSTEP) if (minsteps-- <= 0) break;
last = tp.tv_usec;
}
printf("resolution = %ld usec after %d loop%s\n",
diff, i, (i==1) ? "" : "s");
diff = (diff *3)/2;
if (i >= MAXLOOPS) {
printf(
" (Boy this machine is fast ! %d loops without a step)\n",
MAXLOOPS);
diff = 1; /* No STEP, so FAST machine */
}
if (i == 0) {
printf(
" (The resolution is less than the time to read the clock -- Assume 1us)\n");
diff = 1; /* time to read clock >= resolution */
}
for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i;
printf(" (Oh dear -- that wasn't expected ! I'll guess !)\n");
return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */;
}
/* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */
/*
* This routine calculates the differences between successive calls to
* gettimeofday(). If a difference is less than zero, the us field
* has rolled over to the next second, so we add a second in us. If
* the difference is greater than zero and less than MINSTEP, the
* clock has been advanced by a small amount to avoid standing still.
* If the clock has advanced by a greater amount, then a timer interrupt
* has occurred and this amount represents the precision of the clock.
* In order to guard against spurious values, which could occur if we
* happen to hit a fat interrupt, we do this for MINLOOPS times and
* keep the minimum value obtained.
*/
int
default_get_precision(void)
{
struct timeval tp;
struct timezone tzp;
#ifdef HAVE_GETCLOCK
struct timespec ts;
#endif
long last;
int i;
long diff;
long val;
long usec;
usec = 0;
val = MAXSTEP;
#ifdef HAVE_GETCLOCK
(void) getclock(TIMEOFDAY, &ts);
tp.tv_sec = ts.tv_sec;
tp.tv_usec = ts.tv_nsec / 1000;
#else /* not HAVE_GETCLOCK */
GETTIMEOFDAY(&tp, &tzp);
#endif /* not HAVE_GETCLOCK */
last = tp.tv_usec;
for (i = 0; i < MINLOOPS && usec < HUSECS;) {
#ifdef HAVE_GETCLOCK
(void) getclock(TIMEOFDAY, &ts);
tp.tv_sec = ts.tv_sec;
tp.tv_usec = ts.tv_nsec / 1000;
#else /* not HAVE_GETCLOCK */
GETTIMEOFDAY(&tp, &tzp);
#endif /* not HAVE_GETCLOCK */
diff = tp.tv_usec - last;
last = tp.tv_usec;
if (diff < 0)
diff += DUSECS;
usec += diff;
if (diff > MINSTEP) {
i++;
if (diff < val)
val = diff;
}
}
printf("precision = %ld usec after %d loop%s\n",
val, i, (i == 1) ? "" : "s");
if (usec >= HUSECS) {
printf(" (Boy this machine is fast ! usec was %ld)\n",
usec);
val = MINSTEP; /* val <= MINSTEP; fast machine */
}
diff = HUSECS;
for (i = 0; diff > val; i--)
diff >>= 1;
return (i);
}
|