adjtick.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* adjtimex() tick adjustment test
  2. * by: John Stultz <john.stultz@linaro.org>
  3. * (C) Copyright Linaro Limited 2015
  4. * Licensed under the GPLv2
  5. *
  6. * To build:
  7. * $ gcc adjtick.c -o adjtick -lrt
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <stdlib.h>
  22. #include <sys/time.h>
  23. #include <sys/timex.h>
  24. #include <time.h>
  25. #ifdef KTEST
  26. #include "../kselftest.h"
  27. #else
  28. static inline int ksft_exit_pass(void)
  29. {
  30. exit(0);
  31. }
  32. static inline int ksft_exit_fail(void)
  33. {
  34. exit(1);
  35. }
  36. #endif
  37. #define CLOCK_MONOTONIC_RAW 4
  38. #define NSEC_PER_SEC 1000000000LL
  39. #define USEC_PER_SEC 1000000
  40. #define MILLION 1000000
  41. long systick;
  42. long long llabs(long long val)
  43. {
  44. if (val < 0)
  45. val = -val;
  46. return val;
  47. }
  48. unsigned long long ts_to_nsec(struct timespec ts)
  49. {
  50. return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
  51. }
  52. struct timespec nsec_to_ts(long long ns)
  53. {
  54. struct timespec ts;
  55. ts.tv_sec = ns/NSEC_PER_SEC;
  56. ts.tv_nsec = ns%NSEC_PER_SEC;
  57. return ts;
  58. }
  59. long long diff_timespec(struct timespec start, struct timespec end)
  60. {
  61. long long start_ns, end_ns;
  62. start_ns = ts_to_nsec(start);
  63. end_ns = ts_to_nsec(end);
  64. return end_ns - start_ns;
  65. }
  66. void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
  67. {
  68. struct timespec start, mid, end;
  69. long long diff = 0, tmp;
  70. int i;
  71. clock_gettime(CLOCK_MONOTONIC, mon);
  72. clock_gettime(CLOCK_MONOTONIC_RAW, raw);
  73. /* Try to get a more tightly bound pairing */
  74. for (i = 0; i < 3; i++) {
  75. long long newdiff;
  76. clock_gettime(CLOCK_MONOTONIC, &start);
  77. clock_gettime(CLOCK_MONOTONIC_RAW, &mid);
  78. clock_gettime(CLOCK_MONOTONIC, &end);
  79. newdiff = diff_timespec(start, end);
  80. if (diff == 0 || newdiff < diff) {
  81. diff = newdiff;
  82. *raw = mid;
  83. tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2;
  84. *mon = nsec_to_ts(tmp);
  85. }
  86. }
  87. }
  88. long long get_ppm_drift(void)
  89. {
  90. struct timespec mon_start, raw_start, mon_end, raw_end;
  91. long long delta1, delta2, eppm;
  92. get_monotonic_and_raw(&mon_start, &raw_start);
  93. sleep(15);
  94. get_monotonic_and_raw(&mon_end, &raw_end);
  95. delta1 = diff_timespec(mon_start, mon_end);
  96. delta2 = diff_timespec(raw_start, raw_end);
  97. eppm = (delta1*MILLION)/delta2 - MILLION;
  98. return eppm;
  99. }
  100. int check_tick_adj(long tickval)
  101. {
  102. long long eppm, ppm;
  103. struct timex tx1;
  104. tx1.modes = ADJ_TICK;
  105. tx1.modes |= ADJ_OFFSET;
  106. tx1.modes |= ADJ_FREQUENCY;
  107. tx1.modes |= ADJ_STATUS;
  108. tx1.status = STA_PLL;
  109. tx1.offset = 0;
  110. tx1.freq = 0;
  111. tx1.tick = tickval;
  112. adjtimex(&tx1);
  113. sleep(1);
  114. ppm = ((long long)tickval * MILLION)/systick - MILLION;
  115. printf("Estimating tick (act: %ld usec, %lld ppm): ", tickval, ppm);
  116. eppm = get_ppm_drift();
  117. printf("%lld usec, %lld ppm", systick + (systick * eppm / MILLION), eppm);
  118. tx1.modes = 0;
  119. adjtimex(&tx1);
  120. if (tx1.offset || tx1.freq || tx1.tick != tickval) {
  121. printf(" [ERROR]\n");
  122. printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n");
  123. return -1;
  124. }
  125. /*
  126. * Here we use 100ppm difference as an error bound.
  127. * We likely should see better, but some coarse clocksources
  128. * cannot match the HZ tick size accurately, so we have a
  129. * internal correction factor that doesn't scale exactly
  130. * with the adjustment, resulting in > 10ppm error during
  131. * a 10% adjustment. 100ppm also gives us more breathing
  132. * room for interruptions during the measurement.
  133. */
  134. if (llabs(eppm - ppm) > 100) {
  135. printf(" [FAILED]\n");
  136. return -1;
  137. }
  138. printf(" [OK]\n");
  139. return 0;
  140. }
  141. int main(int argv, char **argc)
  142. {
  143. struct timespec raw;
  144. long tick, max, interval, err;
  145. struct timex tx1;
  146. err = 0;
  147. setbuf(stdout, NULL);
  148. if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
  149. printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
  150. return -1;
  151. }
  152. printf("Each iteration takes about 15 seconds\n");
  153. systick = sysconf(_SC_CLK_TCK);
  154. systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK);
  155. max = systick/10; /* +/- 10% */
  156. interval = max/4; /* in 4 steps each side */
  157. for (tick = (systick - max); tick < (systick + max); tick += interval) {
  158. if (check_tick_adj(tick)) {
  159. err = 1;
  160. break;
  161. }
  162. }
  163. /* Reset things to zero */
  164. tx1.modes = ADJ_TICK;
  165. tx1.modes |= ADJ_OFFSET;
  166. tx1.modes |= ADJ_FREQUENCY;
  167. tx1.offset = 0;
  168. tx1.freq = 0;
  169. tx1.tick = systick;
  170. adjtimex(&tx1);
  171. if (err)
  172. return ksft_exit_fail();
  173. return ksft_exit_pass();
  174. }