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