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 #ifdef KTEST 2951f91cbdSJohn Stultz #include "../kselftest.h" 3051f91cbdSJohn Stultz #else 3151f91cbdSJohn Stultz static inline int ksft_exit_pass(void) 3251f91cbdSJohn Stultz { 3351f91cbdSJohn Stultz exit(0); 3451f91cbdSJohn Stultz } 3551f91cbdSJohn Stultz static inline int ksft_exit_fail(void) 3651f91cbdSJohn Stultz { 3751f91cbdSJohn Stultz exit(1); 3851f91cbdSJohn Stultz } 3951f91cbdSJohn Stultz #endif 4051f91cbdSJohn Stultz 4151f91cbdSJohn Stultz 4251f91cbdSJohn Stultz #define CLOCK_MONOTONIC_RAW 4 4351f91cbdSJohn Stultz #define NSEC_PER_SEC 1000000000LL 4451f91cbdSJohn Stultz 4551f91cbdSJohn Stultz #define shift_right(x, s) ({ \ 4651f91cbdSJohn Stultz __typeof__(x) __x = (x); \ 4751f91cbdSJohn Stultz __typeof__(s) __s = (s); \ 4851f91cbdSJohn Stultz __x < 0 ? -(-__x >> __s) : __x >> __s; \ 4951f91cbdSJohn Stultz }) 5051f91cbdSJohn Stultz 5151f91cbdSJohn Stultz long long llabs(long long val) 5251f91cbdSJohn Stultz { 5351f91cbdSJohn Stultz if (val < 0) 5451f91cbdSJohn Stultz val = -val; 5551f91cbdSJohn Stultz return val; 5651f91cbdSJohn Stultz } 5751f91cbdSJohn Stultz 5851f91cbdSJohn Stultz unsigned long long ts_to_nsec(struct timespec ts) 5951f91cbdSJohn Stultz { 6051f91cbdSJohn Stultz return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; 6151f91cbdSJohn Stultz } 6251f91cbdSJohn Stultz 6351f91cbdSJohn Stultz struct timespec nsec_to_ts(long long ns) 6451f91cbdSJohn Stultz { 6551f91cbdSJohn Stultz struct timespec ts; 6651f91cbdSJohn Stultz 6751f91cbdSJohn Stultz ts.tv_sec = ns/NSEC_PER_SEC; 6851f91cbdSJohn Stultz ts.tv_nsec = ns%NSEC_PER_SEC; 6951f91cbdSJohn Stultz return ts; 7051f91cbdSJohn Stultz } 7151f91cbdSJohn Stultz 7251f91cbdSJohn Stultz long long diff_timespec(struct timespec start, struct timespec end) 7351f91cbdSJohn Stultz { 7451f91cbdSJohn Stultz long long start_ns, end_ns; 7551f91cbdSJohn Stultz 7651f91cbdSJohn Stultz start_ns = ts_to_nsec(start); 7751f91cbdSJohn Stultz end_ns = ts_to_nsec(end); 7851f91cbdSJohn Stultz return end_ns - start_ns; 7951f91cbdSJohn Stultz } 8051f91cbdSJohn Stultz 8151f91cbdSJohn Stultz void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw) 8251f91cbdSJohn Stultz { 8351f91cbdSJohn Stultz struct timespec start, mid, end; 8451f91cbdSJohn Stultz long long diff = 0, tmp; 8551f91cbdSJohn Stultz int i; 8651f91cbdSJohn Stultz 8751f91cbdSJohn Stultz for (i = 0; i < 3; i++) { 8851f91cbdSJohn Stultz long long newdiff; 8951f91cbdSJohn Stultz 9051f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC, &start); 9151f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC_RAW, &mid); 9251f91cbdSJohn Stultz clock_gettime(CLOCK_MONOTONIC, &end); 9351f91cbdSJohn Stultz 9451f91cbdSJohn Stultz newdiff = diff_timespec(start, end); 9551f91cbdSJohn Stultz if (diff == 0 || newdiff < diff) { 9651f91cbdSJohn Stultz diff = newdiff; 9751f91cbdSJohn Stultz *raw = mid; 9851f91cbdSJohn Stultz tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2; 9951f91cbdSJohn Stultz *mon = nsec_to_ts(tmp); 10051f91cbdSJohn Stultz } 10151f91cbdSJohn Stultz } 10251f91cbdSJohn Stultz } 10351f91cbdSJohn Stultz 10451f91cbdSJohn Stultz int main(int argv, char **argc) 10551f91cbdSJohn Stultz { 10651f91cbdSJohn Stultz struct timespec mon, raw, start, end; 10751f91cbdSJohn Stultz long long delta1, delta2, interval, eppm, ppm; 10851f91cbdSJohn Stultz struct timex tx1, tx2; 10951f91cbdSJohn Stultz 11051f91cbdSJohn Stultz setbuf(stdout, NULL); 11151f91cbdSJohn Stultz 11251f91cbdSJohn Stultz if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) { 11351f91cbdSJohn Stultz printf("ERR: NO CLOCK_MONOTONIC_RAW\n"); 11451f91cbdSJohn Stultz return -1; 11551f91cbdSJohn Stultz } 11651f91cbdSJohn Stultz 11751f91cbdSJohn Stultz tx1.modes = 0; 11851f91cbdSJohn Stultz adjtimex(&tx1); 11951f91cbdSJohn Stultz get_monotonic_and_raw(&mon, &raw); 12051f91cbdSJohn Stultz start = mon; 12151f91cbdSJohn Stultz delta1 = diff_timespec(mon, raw); 12251f91cbdSJohn Stultz 12351f91cbdSJohn Stultz if (tx1.offset) 12451f91cbdSJohn Stultz printf("WARNING: ADJ_OFFSET in progress, this will cause inaccurate results\n"); 12551f91cbdSJohn Stultz 12651f91cbdSJohn Stultz printf("Estimating clock drift: "); 12751f91cbdSJohn Stultz sleep(120); 12851f91cbdSJohn Stultz 12951f91cbdSJohn Stultz get_monotonic_and_raw(&mon, &raw); 13051f91cbdSJohn Stultz end = mon; 13151f91cbdSJohn Stultz tx2.modes = 0; 13251f91cbdSJohn Stultz adjtimex(&tx2); 13351f91cbdSJohn Stultz delta2 = diff_timespec(mon, raw); 13451f91cbdSJohn Stultz 13551f91cbdSJohn Stultz interval = diff_timespec(start, end); 13651f91cbdSJohn Stultz 13751f91cbdSJohn Stultz /* calculate measured ppm between MONOTONIC and MONOTONIC_RAW */ 13851f91cbdSJohn Stultz eppm = ((delta2-delta1)*NSEC_PER_SEC)/interval; 13951f91cbdSJohn Stultz eppm = -eppm; 14051f91cbdSJohn Stultz printf("%lld.%i(est)", eppm/1000, abs((int)(eppm%1000))); 14151f91cbdSJohn Stultz 14251f91cbdSJohn Stultz /* Avg the two actual freq samples adjtimex gave us */ 14351f91cbdSJohn Stultz ppm = (tx1.freq + tx2.freq) * 1000 / 2; 14451f91cbdSJohn Stultz ppm = (long long)tx1.freq * 1000; 14551f91cbdSJohn Stultz ppm = shift_right(ppm, 16); 14651f91cbdSJohn Stultz printf(" %lld.%i(act)", ppm/1000, abs((int)(ppm%1000))); 14751f91cbdSJohn Stultz 14851f91cbdSJohn Stultz if (llabs(eppm - ppm) > 1000) { 14951f91cbdSJohn Stultz printf(" [FAILED]\n"); 15051f91cbdSJohn Stultz return ksft_exit_fail(); 15151f91cbdSJohn Stultz } 15251f91cbdSJohn Stultz printf(" [OK]\n"); 15351f91cbdSJohn Stultz return ksft_exit_pass(); 15451f91cbdSJohn Stultz } 155