0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <stdio.h>
0023 #include <unistd.h>
0024 #include <stdlib.h>
0025 #include <sys/time.h>
0026 #include <sys/timex.h>
0027 #include <time.h>
0028 #include "../kselftest.h"
0029
0030 #define CLOCK_MONOTONIC_RAW 4
0031 #define NSEC_PER_SEC 1000000000LL
0032
0033 #define shift_right(x, s) ({ \
0034 __typeof__(x) __x = (x); \
0035 __typeof__(s) __s = (s); \
0036 __x < 0 ? -(-__x >> __s) : __x >> __s; \
0037 })
0038
0039 long long llabs(long long val)
0040 {
0041 if (val < 0)
0042 val = -val;
0043 return val;
0044 }
0045
0046 unsigned long long ts_to_nsec(struct timespec ts)
0047 {
0048 return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
0049 }
0050
0051 struct timespec nsec_to_ts(long long ns)
0052 {
0053 struct timespec ts;
0054
0055 ts.tv_sec = ns/NSEC_PER_SEC;
0056 ts.tv_nsec = ns%NSEC_PER_SEC;
0057 return ts;
0058 }
0059
0060 long long diff_timespec(struct timespec start, struct timespec end)
0061 {
0062 long long start_ns, end_ns;
0063
0064 start_ns = ts_to_nsec(start);
0065 end_ns = ts_to_nsec(end);
0066 return end_ns - start_ns;
0067 }
0068
0069 void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
0070 {
0071 struct timespec start, mid, end;
0072 long long diff = 0, tmp;
0073 int i;
0074
0075 for (i = 0; i < 3; i++) {
0076 long long newdiff;
0077
0078 clock_gettime(CLOCK_MONOTONIC, &start);
0079 clock_gettime(CLOCK_MONOTONIC_RAW, &mid);
0080 clock_gettime(CLOCK_MONOTONIC, &end);
0081
0082 newdiff = diff_timespec(start, end);
0083 if (diff == 0 || newdiff < diff) {
0084 diff = newdiff;
0085 *raw = mid;
0086 tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2;
0087 *mon = nsec_to_ts(tmp);
0088 }
0089 }
0090 }
0091
0092 int main(int argc, char **argv)
0093 {
0094 struct timespec mon, raw, start, end;
0095 long long delta1, delta2, interval, eppm, ppm;
0096 struct timex tx1, tx2;
0097
0098 setbuf(stdout, NULL);
0099
0100 if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
0101 printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
0102 return -1;
0103 }
0104
0105 tx1.modes = 0;
0106 adjtimex(&tx1);
0107 get_monotonic_and_raw(&mon, &raw);
0108 start = mon;
0109 delta1 = diff_timespec(mon, raw);
0110
0111 if (tx1.offset)
0112 printf("WARNING: ADJ_OFFSET in progress, this will cause inaccurate results\n");
0113
0114 printf("Estimating clock drift: ");
0115 fflush(stdout);
0116 sleep(120);
0117
0118 get_monotonic_and_raw(&mon, &raw);
0119 end = mon;
0120 tx2.modes = 0;
0121 adjtimex(&tx2);
0122 delta2 = diff_timespec(mon, raw);
0123
0124 interval = diff_timespec(start, end);
0125
0126
0127 eppm = ((delta2-delta1)*NSEC_PER_SEC)/interval;
0128 eppm = -eppm;
0129 printf("%lld.%i(est)", eppm/1000, abs((int)(eppm%1000)));
0130
0131
0132 ppm = (tx1.freq + tx2.freq) * 1000 / 2;
0133 ppm = (long long)tx1.freq * 1000;
0134 ppm = shift_right(ppm, 16);
0135 printf(" %lld.%i(act)", ppm/1000, abs((int)(ppm%1000)));
0136
0137 if (llabs(eppm - ppm) > 1000) {
0138 if (tx1.offset || tx2.offset ||
0139 tx1.freq != tx2.freq || tx1.tick != tx2.tick) {
0140 printf(" [SKIP]\n");
0141 return ksft_exit_skip("The clock was adjusted externally. Shutdown NTPd or other time sync daemons\n");
0142 }
0143 printf(" [FAILED]\n");
0144 return ksft_exit_fail();
0145 }
0146 printf(" [OK]\n");
0147 return ksft_exit_pass();
0148 }