adjtick.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* adjtimex() tick adjustment test
  2. * by: John Stultz <[email protected]>
  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. #include "../kselftest.h"
  26. #define CLOCK_MONOTONIC_RAW 4
  27. #define NSEC_PER_SEC 1000000000LL
  28. #define USEC_PER_SEC 1000000
  29. #define MILLION 1000000
  30. long systick;
  31. long long llabs(long long val)
  32. {
  33. if (val < 0)
  34. val = -val;
  35. return val;
  36. }
  37. unsigned long long ts_to_nsec(struct timespec ts)
  38. {
  39. return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
  40. }
  41. struct timespec nsec_to_ts(long long ns)
  42. {
  43. struct timespec ts;
  44. ts.tv_sec = ns/NSEC_PER_SEC;
  45. ts.tv_nsec = ns%NSEC_PER_SEC;
  46. return ts;
  47. }
  48. long long diff_timespec(struct timespec start, struct timespec end)
  49. {
  50. long long start_ns, end_ns;
  51. start_ns = ts_to_nsec(start);
  52. end_ns = ts_to_nsec(end);
  53. return end_ns - start_ns;
  54. }
  55. void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
  56. {
  57. struct timespec start, mid, end;
  58. long long diff = 0, tmp;
  59. int i;
  60. clock_gettime(CLOCK_MONOTONIC, mon);
  61. clock_gettime(CLOCK_MONOTONIC_RAW, raw);
  62. /* Try to get a more tightly bound pairing */
  63. for (i = 0; i < 3; i++) {
  64. long long newdiff;
  65. clock_gettime(CLOCK_MONOTONIC, &start);
  66. clock_gettime(CLOCK_MONOTONIC_RAW, &mid);
  67. clock_gettime(CLOCK_MONOTONIC, &end);
  68. newdiff = diff_timespec(start, end);
  69. if (diff == 0 || newdiff < diff) {
  70. diff = newdiff;
  71. *raw = mid;
  72. tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2;
  73. *mon = nsec_to_ts(tmp);
  74. }
  75. }
  76. }
  77. long long get_ppm_drift(void)
  78. {
  79. struct timespec mon_start, raw_start, mon_end, raw_end;
  80. long long delta1, delta2, eppm;
  81. get_monotonic_and_raw(&mon_start, &raw_start);
  82. sleep(15);
  83. get_monotonic_and_raw(&mon_end, &raw_end);
  84. delta1 = diff_timespec(mon_start, mon_end);
  85. delta2 = diff_timespec(raw_start, raw_end);
  86. eppm = (delta1*MILLION)/delta2 - MILLION;
  87. return eppm;
  88. }
  89. int check_tick_adj(long tickval)
  90. {
  91. long long eppm, ppm;
  92. struct timex tx1;
  93. tx1.modes = ADJ_TICK;
  94. tx1.modes |= ADJ_OFFSET;
  95. tx1.modes |= ADJ_FREQUENCY;
  96. tx1.modes |= ADJ_STATUS;
  97. tx1.status = STA_PLL;
  98. tx1.offset = 0;
  99. tx1.freq = 0;
  100. tx1.tick = tickval;
  101. adjtimex(&tx1);
  102. sleep(1);
  103. ppm = ((long long)tickval * MILLION)/systick - MILLION;
  104. printf("Estimating tick (act: %ld usec, %lld ppm): ", tickval, ppm);
  105. eppm = get_ppm_drift();
  106. printf("%lld usec, %lld ppm", systick + (systick * eppm / MILLION), eppm);
  107. fflush(stdout);
  108. tx1.modes = 0;
  109. adjtimex(&tx1);
  110. if (tx1.offset || tx1.freq || tx1.tick != tickval) {
  111. printf(" [ERROR]\n");
  112. printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n");
  113. return -1;
  114. }
  115. /*
  116. * Here we use 100ppm difference as an error bound.
  117. * We likely should see better, but some coarse clocksources
  118. * cannot match the HZ tick size accurately, so we have a
  119. * internal correction factor that doesn't scale exactly
  120. * with the adjustment, resulting in > 10ppm error during
  121. * a 10% adjustment. 100ppm also gives us more breathing
  122. * room for interruptions during the measurement.
  123. */
  124. if (llabs(eppm - ppm) > 100) {
  125. printf(" [FAILED]\n");
  126. return -1;
  127. }
  128. printf(" [OK]\n");
  129. return 0;
  130. }
  131. int main(int argc, char **argv)
  132. {
  133. struct timespec raw;
  134. long tick, max, interval, err;
  135. struct timex tx1;
  136. err = 0;
  137. setbuf(stdout, NULL);
  138. if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
  139. printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
  140. return -1;
  141. }
  142. printf("Each iteration takes about 15 seconds\n");
  143. systick = sysconf(_SC_CLK_TCK);
  144. systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK);
  145. max = systick/10; /* +/- 10% */
  146. interval = max/4; /* in 4 steps each side */
  147. for (tick = (systick - max); tick < (systick + max); tick += interval) {
  148. if (check_tick_adj(tick)) {
  149. err = 1;
  150. break;
  151. }
  152. }
  153. /* Reset things to zero */
  154. tx1.modes = ADJ_TICK;
  155. tx1.modes |= ADJ_OFFSET;
  156. tx1.modes |= ADJ_FREQUENCY;
  157. tx1.offset = 0;
  158. tx1.freq = 0;
  159. tx1.tick = systick;
  160. adjtimex(&tx1);
  161. if (err)
  162. return ksft_exit_fail();
  163. return ksft_exit_pass();
  164. }