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