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