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