PageRenderTime 26ms CodeModel.GetById 2ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/ntp/util/precision.c

https://bitbucket.org/freebsd/freebsd-head/
C | 171 lines | 113 code | 13 blank | 45 comment | 17 complexity | f5246d96c624a57178429a5ba4dcb965 MD5 | raw file
  1#include "ntp_unixtime.h"
  2
  3#include <stdio.h>
  4
  5#define	DEFAULT_SYS_PRECISION	-99
  6
  7int default_get_resolution();
  8int default_get_precision();
  9
 10int
 11main(
 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
 62int
 63default_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 */  
117int
118default_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}