1 #include "ntp_unixtime.h" 2 3 #include <stdio.h> 4 5 #define DEFAULT_SYS_PRECISION -99 6 7 int default_get_resolution(); 8 int default_get_precision(); 9 10 int 11 main( 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 62 int 63 default_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 */ 117 int 118 default_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 } 172