151f91cbdSJohn Stultz /* CLOCK_MONOTONIC vs CLOCK_MONOTONIC_RAW skew test 251f91cbdSJohn Stultz * by: john stultz (johnstul@us.ibm.com) 351f91cbdSJohn Stultz * John Stultz <john.stultz@linaro.org> 451f91cbdSJohn Stultz * (C) Copyright IBM 2012 551f91cbdSJohn Stultz * (C) Copyright Linaro Limited 2015 651f91cbdSJohn Stultz * Licensed under the GPLv2 751f91cbdSJohn Stultz * 851f91cbdSJohn Stultz * To build: 951f91cbdSJohn Stultz * $ gcc raw_skew.c -o raw_skew -lrt 1051f91cbdSJohn Stultz * 1151f91cbdSJohn Stultz * This program is free software: you can redistribute it and/or modify 1251f91cbdSJohn Stultz * it under the terms of the GNU General Public License as published by 1351f91cbdSJohn Stultz * the Free Software Foundation, either version 2 of the License, or 1451f91cbdSJohn Stultz * (at your option) any later version. 1551f91cbdSJohn Stultz * 1651f91cbdSJohn Stultz * This program is distributed in the hope that it will be useful, 1751f91cbdSJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 1851f91cbdSJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1951f91cbdSJohn Stultz * GNU General Public License for more details. 2051f91cbdSJohn Stultz */ 2151f91cbdSJohn Stultz 2251f91cbdSJohn Stultz #include <stdio.h> 2351f91cbdSJohn Stultz #include <unistd.h> 2451f91cbdSJohn Stultz #include <stdlib.h> 2551f91cbdSJohn Stultz #include <sys/time.h> 2651f91cbdSJohn Stultz #include <sys/timex.h> 2751f91cbdSJohn Stultz #include <time.h> 2851f91cbdSJohn Stultz #include "../kselftest.h" 2951f91cbdSJohn Stultz 3051f91cbdSJohn Stultz #define CLOCK_MONOTONIC_RAW 4 3151f91cbdSJohn Stultz #define NSEC_PER_SEC 1000000000LL 3251f91cbdSJohn Stultz 3351f91cbdSJohn Stultz #define shift_right(x, s) ({ \ 3451f91cbdSJohn Stultz __typeof__(x) __x = (x); \ 3551f91cbdSJohn Stultz __typeof__(s) __s = (s); \ 3651f91cbdSJohn Stultz __x < 0 ? -(-__x >> __s) : __x >> __s; \ 3751f91cbdSJohn Stultz }) 3851f91cbdSJohn Stultz 3951f91cbdSJohn Stultz long long llabs(long long val) 4051f91cbdSJohn Stultz { 4151f91cbdSJohn Stultz if (val < 0) 4251f91cbdSJohn Stultz val = -val; 4351f91cbdSJohn Stultz return val; 4451f91cbdSJohn Stultz } 4551f91cbdSJohn Stultz 4651f91cbdSJohn Stultz unsigned long long ts_to_nsec(struct timespec ts) 4751f91cbdSJohn Stultz { 4851f91cbdSJohn Stultz return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; 4951f91cbdSJohn Stultz } 5051f91cbdSJohn Stultz 5151f91cbdSJohn Stultz struct timespec nsec_to_ts(long long ns) 5251f91cbdSJohn Stultz { 5351f91cbdSJohn Stultz struct timespec ts; 5451f91cbdSJohn Stultz 5551f91cbdSJohn Stultz ts.tv_sec = ns/NSEC_PER_SEC; 5651f91cbdSJohn Stultz ts.tv_nsec = ns%NSEC_PER_SEC; 5751f91cbdSJohn Stultz return ts; 5851f91cbdSJohn Stultz } 5951f91cbdSJohn Stultz 6051f91cbdSJohn Stultz long long diff_timespec(struct timespec start, struct timespec end) 6151f91cbdSJohn Stultz { 6251f91cbdSJohn Stultz long long start_ns, end_ns; 6351f91cbdSJohn Stultz 6451f91cbdSJohn Stultz start_ns = ts_to_nsec(start); 6551f91cbdSJohn Stultz end_ns = ts_to_nsec(end); 6651f91cbdSJohn Stultz return end_ns - start_ns; 6751f91cbdSJohn Stultz } 6851f91cbdSJohn Stultz 6951f91cbdSJohn Stultz void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw) 7051f91cbdSJohn Stultz { 7151f91cbdSJohn Stultz struct timespec start, mid, end; 7251f91cbdSJohn Stultz long long diff = 0, tmp; 7351f91cbdSJohn Stultz int i; 7451f91cbdSJohn Stultz 7551f91cbdSJohn Stultz for (i = 0; i < 3; i++) { 7651f91cbdSJohn Stultz long long newdiff; 7751f91cbdSJohn Stultz 7851f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC, &start); 7951f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC_RAW, &mid); 8051f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC, &end); 8151f91cbdSJohn Stultz 8251f91cbdSJohn Stultz newdiff = diff_timespec(start, end); 8351f91cbdSJohn Stultz if (diff == 0 || newdiff < diff) { 8451f91cbdSJohn Stultz diff = newdiff; 8551f91cbdSJohn Stultz *raw = mid; 8651f91cbdSJohn Stultz tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2; 8751f91cbdSJohn Stultz *mon = nsec_to_ts(tmp); 8851f91cbdSJohn Stultz } 8951f91cbdSJohn Stultz } 9051f91cbdSJohn Stultz } 9151f91cbdSJohn Stultz 92*a8d74fe7SWolfram Sang int main(int argc, char **argv) 9351f91cbdSJohn Stultz { 9451f91cbdSJohn Stultz struct timespec mon, raw, start, end; 9551f91cbdSJohn Stultz long long delta1, delta2, interval, eppm, ppm; 9651f91cbdSJohn Stultz struct timex tx1, tx2; 9751f91cbdSJohn Stultz 9851f91cbdSJohn Stultz setbuf(stdout, NULL); 9951f91cbdSJohn Stultz 10051f91cbdSJohn Stultz if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) { 10151f91cbdSJohn Stultz printf("ERR: NO CLOCK_MONOTONIC_RAW\n"); 10251f91cbdSJohn Stultz return -1; 10351f91cbdSJohn Stultz } 10451f91cbdSJohn Stultz 10551f91cbdSJohn Stultz tx1.modes = 0; 10651f91cbdSJohn Stultz adjtimex(&tx1); 10751f91cbdSJohn Stultz get_monotonic_and_raw(&mon, &raw); 10851f91cbdSJohn Stultz start = mon; 10951f91cbdSJohn Stultz delta1 = diff_timespec(mon, raw); 11051f91cbdSJohn Stultz 11151f91cbdSJohn Stultz if (tx1.offset) 11251f91cbdSJohn Stultz printf("WARNING: ADJ_OFFSET in progress, this will cause inaccurate results\n"); 11351f91cbdSJohn Stultz 11451f91cbdSJohn Stultz printf("Estimating clock drift: "); 115fe483192SKees Cook fflush(stdout); 11651f91cbdSJohn Stultz sleep(120); 11751f91cbdSJohn Stultz 11851f91cbdSJohn Stultz get_monotonic_and_raw(&mon, &raw); 11951f91cbdSJohn Stultz end = mon; 12051f91cbdSJohn Stultz tx2.modes = 0; 12151f91cbdSJohn Stultz adjtimex(&tx2); 12251f91cbdSJohn Stultz delta2 = diff_timespec(mon, raw); 12351f91cbdSJohn Stultz 12451f91cbdSJohn Stultz interval = diff_timespec(start, end); 12551f91cbdSJohn Stultz 12651f91cbdSJohn Stultz /* calculate measured ppm between MONOTONIC and MONOTONIC_RAW */ 12751f91cbdSJohn Stultz eppm = ((delta2-delta1)*NSEC_PER_SEC)/interval; 12851f91cbdSJohn Stultz eppm = -eppm; 12951f91cbdSJohn Stultz printf("%lld.%i(est)", eppm/1000, abs((int)(eppm%1000))); 13051f91cbdSJohn Stultz 13151f91cbdSJohn Stultz /* Avg the two actual freq samples adjtimex gave us */ 13251f91cbdSJohn Stultz ppm = (tx1.freq + tx2.freq) * 1000 / 2; 13351f91cbdSJohn Stultz ppm = (long long)tx1.freq * 1000; 13451f91cbdSJohn Stultz ppm = shift_right(ppm, 16); 13551f91cbdSJohn Stultz printf(" %lld.%i(act)", ppm/1000, abs((int)(ppm%1000))); 13651f91cbdSJohn Stultz 13751f91cbdSJohn Stultz if (llabs(eppm - ppm) > 1000) { 1381416270fSJohn Stultz if (tx1.offset || tx2.offset || 1391416270fSJohn Stultz tx1.freq != tx2.freq || tx1.tick != tx2.tick) { 1401416270fSJohn Stultz printf(" [SKIP]\n"); 1411416270fSJohn Stultz return ksft_exit_skip("The clock was adjusted externally. Shutdown NTPd or other time sync daemons\n"); 1421416270fSJohn Stultz } 14351f91cbdSJohn Stultz printf(" [FAILED]\n"); 14451f91cbdSJohn Stultz return ksft_exit_fail(); 14551f91cbdSJohn Stultz } 14651f91cbdSJohn Stultz printf(" [OK]\n"); 14751f91cbdSJohn Stultz return ksft_exit_pass(); 14851f91cbdSJohn Stultz } 149