154359Sroberto#include "ntp_unixtime.h" 254359Sroberto 382498Sroberto#include <stdio.h> 482498Sroberto 554359Sroberto#define DEFAULT_SYS_PRECISION -99 654359Sroberto 754359Srobertoint default_get_resolution(); 854359Srobertoint default_get_precision(); 954359Sroberto 1054359Srobertoint 1154359Srobertomain( 1254359Sroberto int argc, 1354359Sroberto char *argv[] 1454359Sroberto ) 1554359Sroberto{ 1654359Sroberto printf("log2(resolution) = %d, log2(precision) = %d\n", 1754359Sroberto default_get_resolution(), 1854359Sroberto default_get_precision()); 1954359Sroberto return 0; 2054359Sroberto} 2154359Sroberto 2254359Sroberto/* Find the resolution of the system clock by watching how the current time 2354359Sroberto * changes as we read it repeatedly. 2454359Sroberto * 2554359Sroberto * struct timeval is only good to 1us, which may cause problems as machines 2654359Sroberto * get faster, but until then the logic goes: 2754359Sroberto * 2854359Sroberto * If a machine has resolution (i.e. accurate timing info) > 1us, then it will 2954359Sroberto * probably use the "unused" low order bits as a counter (to force time to be 3054359Sroberto * a strictly increaing variable), incrementing it each time any process 3154359Sroberto * requests the time [[ or maybe time will stand still ? ]]. 3254359Sroberto * 3354359Sroberto * SO: the logic goes: 3454359Sroberto * 3554359Sroberto * IF the difference from the last time is "small" (< MINSTEP) 3654359Sroberto * THEN this machine is "counting" with the low order bits 3754359Sroberto * ELIF this is not the first time round the loop 3854359Sroberto * THEN this machine *WAS* counting, and has now stepped 3954359Sroberto * ELSE this machine has resolution < time to read clock 4054359Sroberto * 4154359Sroberto * SO: if it exits on the first loop, assume "full accuracy" (1us) 4254359Sroberto * otherwise, take the log2(observered difference, rounded UP) 4354359Sroberto * 4454359Sroberto * MINLOOPS > 1 ensures that even if there is a STEP between the initial call 4554359Sroberto * and the first loop, it doesn't stop too early. 4654359Sroberto * Making it even greater allows MINSTEP to be reduced, assuming that the 4754359Sroberto * chance of MINSTEP-1 other processes getting in and calling gettimeofday 4854359Sroberto * between this processes's calls. 4954359Sroberto * Reducing MINSTEP may be necessary as this sets an upper bound for the time 5054359Sroberto * to actually call gettimeofday. 5154359Sroberto */ 5254359Sroberto 5354359Sroberto#define DUSECS 1000000 5454359Sroberto#define HUSECS (1024 * 1024) 5554359Sroberto#define MINSTEP 5 /* some systems increment uS on each call */ 5654359Sroberto/* Don't use "1" as some *other* process may read too*/ 5754359Sroberto/*We assume no system actually *ANSWERS* in this time*/ 5854359Sroberto#define MAXSTEP 20000 /* maximum clock increment (us) */ 5954359Sroberto#define MINLOOPS 5 /* minimum number of step samples */ 6054359Sroberto#define MAXLOOPS HUSECS /* Assume precision < .1s ! */ 6154359Sroberto 6254359Srobertoint 6354359Srobertodefault_get_resolution(void) 6454359Sroberto{ 6554359Sroberto struct timeval tp; 6654359Sroberto struct timezone tzp; 6754359Sroberto long last; 6854359Sroberto int i; 6954359Sroberto long diff; 7054359Sroberto long val; 7154359Sroberto int minsteps = MINLOOPS; /* need at least this many steps */ 7254359Sroberto 7354359Sroberto gettimeofday(&tp, &tzp); 7454359Sroberto last = tp.tv_usec; 7554359Sroberto for (i = - --minsteps; i< MAXLOOPS; i++) { 7654359Sroberto gettimeofday(&tp, &tzp); 7754359Sroberto diff = tp.tv_usec - last; 7854359Sroberto if (diff < 0) diff += DUSECS; 7954359Sroberto if (diff > MINSTEP) if (minsteps-- <= 0) break; 8054359Sroberto last = tp.tv_usec; 8154359Sroberto } 8254359Sroberto 8354359Sroberto printf("resolution = %ld usec after %d loop%s\n", 8454359Sroberto diff, i, (i==1) ? "" : "s"); 8554359Sroberto 8654359Sroberto diff = (diff *3)/2; 8754359Sroberto if (i >= MAXLOOPS) { 8854359Sroberto printf( 8954359Sroberto " (Boy this machine is fast ! %d loops without a step)\n", 9054359Sroberto MAXLOOPS); 9154359Sroberto diff = 1; /* No STEP, so FAST machine */ 9254359Sroberto } 9354359Sroberto if (i == 0) { 9454359Sroberto printf( 9554359Sroberto " (The resolution is less than the time to read the clock -- Assume 1us)\n"); 9654359Sroberto diff = 1; /* time to read clock >= resolution */ 9754359Sroberto } 9854359Sroberto for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; 9954359Sroberto printf(" (Oh dear -- that wasn't expected ! I'll guess !)\n"); 10054359Sroberto return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; 10154359Sroberto} 10254359Sroberto 10354359Sroberto/* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */ 10454359Sroberto 10554359Sroberto/* 10654359Sroberto * This routine calculates the differences between successive calls to 10754359Sroberto * gettimeofday(). If a difference is less than zero, the us field 10854359Sroberto * has rolled over to the next second, so we add a second in us. If 10954359Sroberto * the difference is greater than zero and less than MINSTEP, the 11054359Sroberto * clock has been advanced by a small amount to avoid standing still. 11154359Sroberto * If the clock has advanced by a greater amount, then a timer interrupt 11254359Sroberto * has occurred and this amount represents the precision of the clock. 11354359Sroberto * In order to guard against spurious values, which could occur if we 11454359Sroberto * happen to hit a fat interrupt, we do this for MINLOOPS times and 11554359Sroberto * keep the minimum value obtained. 11654359Sroberto */ 11754359Srobertoint 11854359Srobertodefault_get_precision(void) 11954359Sroberto{ 12054359Sroberto struct timeval tp; 12154359Sroberto struct timezone tzp; 12254359Sroberto#ifdef HAVE_GETCLOCK 12354359Sroberto struct timespec ts; 12454359Sroberto#endif 12554359Sroberto long last; 12654359Sroberto int i; 12754359Sroberto long diff; 12854359Sroberto long val; 12954359Sroberto long usec; 13054359Sroberto 13154359Sroberto usec = 0; 13254359Sroberto val = MAXSTEP; 13354359Sroberto#ifdef HAVE_GETCLOCK 13454359Sroberto (void) getclock(TIMEOFDAY, &ts); 13554359Sroberto tp.tv_sec = ts.tv_sec; 13654359Sroberto tp.tv_usec = ts.tv_nsec / 1000; 13754359Sroberto#else /* not HAVE_GETCLOCK */ 13854359Sroberto GETTIMEOFDAY(&tp, &tzp); 13954359Sroberto#endif /* not HAVE_GETCLOCK */ 14054359Sroberto last = tp.tv_usec; 14154359Sroberto for (i = 0; i < MINLOOPS && usec < HUSECS;) { 14254359Sroberto#ifdef HAVE_GETCLOCK 14354359Sroberto (void) getclock(TIMEOFDAY, &ts); 14454359Sroberto tp.tv_sec = ts.tv_sec; 14554359Sroberto tp.tv_usec = ts.tv_nsec / 1000; 14654359Sroberto#else /* not HAVE_GETCLOCK */ 14754359Sroberto GETTIMEOFDAY(&tp, &tzp); 14854359Sroberto#endif /* not HAVE_GETCLOCK */ 14954359Sroberto diff = tp.tv_usec - last; 15054359Sroberto last = tp.tv_usec; 15154359Sroberto if (diff < 0) 15254359Sroberto diff += DUSECS; 15354359Sroberto usec += diff; 15454359Sroberto if (diff > MINSTEP) { 15554359Sroberto i++; 15654359Sroberto if (diff < val) 15754359Sroberto val = diff; 15854359Sroberto } 15954359Sroberto } 16054359Sroberto printf("precision = %ld usec after %d loop%s\n", 16154359Sroberto val, i, (i == 1) ? "" : "s"); 16254359Sroberto if (usec >= HUSECS) { 16354359Sroberto printf(" (Boy this machine is fast ! usec was %ld)\n", 16454359Sroberto usec); 16554359Sroberto val = MINSTEP; /* val <= MINSTEP; fast machine */ 16654359Sroberto } 16754359Sroberto diff = HUSECS; 16854359Sroberto for (i = 0; diff > val; i--) 16954359Sroberto diff >>= 1; 17054359Sroberto return (i); 17154359Sroberto} 172