1ed3fe34aSJohn Stultz /* Time inconsistency check test 2ed3fe34aSJohn Stultz * by: john stultz (johnstul@us.ibm.com) 3ed3fe34aSJohn Stultz * (C) Copyright IBM 2003, 2004, 2005, 2012 4ed3fe34aSJohn Stultz * (C) Copyright Linaro Limited 2015 5ed3fe34aSJohn Stultz * Licensed under the GPLv2 6ed3fe34aSJohn Stultz * 7ed3fe34aSJohn Stultz * To build: 8ed3fe34aSJohn Stultz * $ gcc inconsistency-check.c -o inconsistency-check -lrt 9ed3fe34aSJohn Stultz * 10ed3fe34aSJohn Stultz * This program is free software: you can redistribute it and/or modify 11ed3fe34aSJohn Stultz * it under the terms of the GNU General Public License as published by 12ed3fe34aSJohn Stultz * the Free Software Foundation, either version 2 of the License, or 13ed3fe34aSJohn Stultz * (at your option) any later version. 14ed3fe34aSJohn Stultz * 15ed3fe34aSJohn Stultz * This program is distributed in the hope that it will be useful, 16ed3fe34aSJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 17ed3fe34aSJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18ed3fe34aSJohn Stultz * GNU General Public License for more details. 19ed3fe34aSJohn Stultz */ 20ed3fe34aSJohn Stultz 21ed3fe34aSJohn Stultz 22ed3fe34aSJohn Stultz 23ed3fe34aSJohn Stultz #include <stdio.h> 24ed3fe34aSJohn Stultz #include <unistd.h> 25ed3fe34aSJohn Stultz #include <stdlib.h> 26ed3fe34aSJohn Stultz #include <time.h> 27ed3fe34aSJohn Stultz #include <sys/time.h> 28ed3fe34aSJohn Stultz #include <sys/timex.h> 29ed3fe34aSJohn Stultz #include <string.h> 30ed3fe34aSJohn Stultz #include <signal.h> 31ed3fe34aSJohn Stultz #ifdef KTEST 32ed3fe34aSJohn Stultz #include "../kselftest.h" 33ed3fe34aSJohn Stultz #else 34ed3fe34aSJohn Stultz static inline int ksft_exit_pass(void) 35ed3fe34aSJohn Stultz { 36ed3fe34aSJohn Stultz exit(0); 37ed3fe34aSJohn Stultz } 38ed3fe34aSJohn Stultz static inline int ksft_exit_fail(void) 39ed3fe34aSJohn Stultz { 40ed3fe34aSJohn Stultz exit(1); 41ed3fe34aSJohn Stultz } 42ed3fe34aSJohn Stultz #endif 43ed3fe34aSJohn Stultz 44ed3fe34aSJohn Stultz #define CALLS_PER_LOOP 64 45ed3fe34aSJohn Stultz #define NSEC_PER_SEC 1000000000ULL 46ed3fe34aSJohn Stultz 47ed3fe34aSJohn Stultz #define CLOCK_REALTIME 0 48ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC 1 49ed3fe34aSJohn Stultz #define CLOCK_PROCESS_CPUTIME_ID 2 50ed3fe34aSJohn Stultz #define CLOCK_THREAD_CPUTIME_ID 3 51ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC_RAW 4 52ed3fe34aSJohn Stultz #define CLOCK_REALTIME_COARSE 5 53ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC_COARSE 6 54ed3fe34aSJohn Stultz #define CLOCK_BOOTTIME 7 55ed3fe34aSJohn Stultz #define CLOCK_REALTIME_ALARM 8 56ed3fe34aSJohn Stultz #define CLOCK_BOOTTIME_ALARM 9 57ed3fe34aSJohn Stultz #define CLOCK_HWSPECIFIC 10 58ed3fe34aSJohn Stultz #define CLOCK_TAI 11 59ed3fe34aSJohn Stultz #define NR_CLOCKIDS 12 60ed3fe34aSJohn Stultz 61ed3fe34aSJohn Stultz char *clockstring(int clockid) 62ed3fe34aSJohn Stultz { 63ed3fe34aSJohn Stultz switch (clockid) { 64ed3fe34aSJohn Stultz case CLOCK_REALTIME: 65ed3fe34aSJohn Stultz return "CLOCK_REALTIME"; 66ed3fe34aSJohn Stultz case CLOCK_MONOTONIC: 67ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC"; 68ed3fe34aSJohn Stultz case CLOCK_PROCESS_CPUTIME_ID: 69ed3fe34aSJohn Stultz return "CLOCK_PROCESS_CPUTIME_ID"; 70ed3fe34aSJohn Stultz case CLOCK_THREAD_CPUTIME_ID: 71ed3fe34aSJohn Stultz return "CLOCK_THREAD_CPUTIME_ID"; 72ed3fe34aSJohn Stultz case CLOCK_MONOTONIC_RAW: 73ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC_RAW"; 74ed3fe34aSJohn Stultz case CLOCK_REALTIME_COARSE: 75ed3fe34aSJohn Stultz return "CLOCK_REALTIME_COARSE"; 76ed3fe34aSJohn Stultz case CLOCK_MONOTONIC_COARSE: 77ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC_COARSE"; 78ed3fe34aSJohn Stultz case CLOCK_BOOTTIME: 79ed3fe34aSJohn Stultz return "CLOCK_BOOTTIME"; 80ed3fe34aSJohn Stultz case CLOCK_REALTIME_ALARM: 81ed3fe34aSJohn Stultz return "CLOCK_REALTIME_ALARM"; 82ed3fe34aSJohn Stultz case CLOCK_BOOTTIME_ALARM: 83ed3fe34aSJohn Stultz return "CLOCK_BOOTTIME_ALARM"; 84ed3fe34aSJohn Stultz case CLOCK_TAI: 85ed3fe34aSJohn Stultz return "CLOCK_TAI"; 86ed3fe34aSJohn Stultz }; 87ed3fe34aSJohn Stultz return "UNKNOWN_CLOCKID"; 88ed3fe34aSJohn Stultz } 89ed3fe34aSJohn Stultz 90ed3fe34aSJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 91ed3fe34aSJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 92ed3fe34aSJohn Stultz { 93ed3fe34aSJohn Stultz /* use unsigned to avoid false positives on 2038 rollover */ 94ed3fe34aSJohn Stultz if ((unsigned long)a.tv_sec < (unsigned long)b.tv_sec) 95ed3fe34aSJohn Stultz return 1; 96ed3fe34aSJohn Stultz if ((unsigned long)a.tv_sec > (unsigned long)b.tv_sec) 97ed3fe34aSJohn Stultz return 0; 98ed3fe34aSJohn Stultz if (a.tv_nsec > b.tv_nsec) 99ed3fe34aSJohn Stultz return 0; 100ed3fe34aSJohn Stultz return 1; 101ed3fe34aSJohn Stultz } 102ed3fe34aSJohn Stultz 103ed3fe34aSJohn Stultz 104ed3fe34aSJohn Stultz 105ed3fe34aSJohn Stultz int consistency_test(int clock_type, unsigned long seconds) 106ed3fe34aSJohn Stultz { 107ed3fe34aSJohn Stultz struct timespec list[CALLS_PER_LOOP]; 108ed3fe34aSJohn Stultz int i, inconsistent; 109ed3fe34aSJohn Stultz long now, then; 110ed3fe34aSJohn Stultz time_t t; 111ed3fe34aSJohn Stultz char *start_str; 112ed3fe34aSJohn Stultz 113ed3fe34aSJohn Stultz clock_gettime(clock_type, &list[0]); 114ed3fe34aSJohn Stultz now = then = list[0].tv_sec; 115ed3fe34aSJohn Stultz 116ed3fe34aSJohn Stultz /* timestamp start of test */ 117ed3fe34aSJohn Stultz t = time(0); 118ed3fe34aSJohn Stultz start_str = ctime(&t); 119ed3fe34aSJohn Stultz 120ed3fe34aSJohn Stultz while (seconds == -1 || now - then < seconds) { 121ed3fe34aSJohn Stultz inconsistent = 0; 122ed3fe34aSJohn Stultz 123ed3fe34aSJohn Stultz /* Fill list */ 124ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP; i++) 125ed3fe34aSJohn Stultz clock_gettime(clock_type, &list[i]); 126ed3fe34aSJohn Stultz 127ed3fe34aSJohn Stultz /* Check for inconsistencies */ 128ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP - 1; i++) 129ed3fe34aSJohn Stultz if (!in_order(list[i], list[i+1])) 130ed3fe34aSJohn Stultz inconsistent = i; 131ed3fe34aSJohn Stultz 132ed3fe34aSJohn Stultz /* display inconsistency */ 133ed3fe34aSJohn Stultz if (inconsistent) { 134ed3fe34aSJohn Stultz unsigned long long delta; 135ed3fe34aSJohn Stultz 136ed3fe34aSJohn Stultz printf("\%s\n", start_str); 137ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP; i++) { 138ed3fe34aSJohn Stultz if (i == inconsistent) 139ed3fe34aSJohn Stultz printf("--------------------\n"); 140ed3fe34aSJohn Stultz printf("%lu:%lu\n", list[i].tv_sec, 141ed3fe34aSJohn Stultz list[i].tv_nsec); 142ed3fe34aSJohn Stultz if (i == inconsistent + 1) 143ed3fe34aSJohn Stultz printf("--------------------\n"); 144ed3fe34aSJohn Stultz } 145ed3fe34aSJohn Stultz delta = list[inconsistent].tv_sec * NSEC_PER_SEC; 146ed3fe34aSJohn Stultz delta += list[inconsistent].tv_nsec; 147ed3fe34aSJohn Stultz delta -= list[inconsistent+1].tv_sec * NSEC_PER_SEC; 148ed3fe34aSJohn Stultz delta -= list[inconsistent+1].tv_nsec; 149ed3fe34aSJohn Stultz printf("Delta: %llu ns\n", delta); 150ed3fe34aSJohn Stultz fflush(0); 151ed3fe34aSJohn Stultz /* timestamp inconsistency*/ 152ed3fe34aSJohn Stultz t = time(0); 153ed3fe34aSJohn Stultz printf("%s\n", ctime(&t)); 154ed3fe34aSJohn Stultz printf("[FAILED]\n"); 155ed3fe34aSJohn Stultz return -1; 156ed3fe34aSJohn Stultz } 157ed3fe34aSJohn Stultz now = list[0].tv_sec; 158ed3fe34aSJohn Stultz } 159ed3fe34aSJohn Stultz printf("[OK]\n"); 160ed3fe34aSJohn Stultz return 0; 161ed3fe34aSJohn Stultz } 162ed3fe34aSJohn Stultz 163ed3fe34aSJohn Stultz 164ed3fe34aSJohn Stultz int main(int argc, char *argv[]) 165ed3fe34aSJohn Stultz { 166ed3fe34aSJohn Stultz int clockid, opt; 167ed3fe34aSJohn Stultz int userclock = CLOCK_REALTIME; 168ed3fe34aSJohn Stultz int maxclocks = NR_CLOCKIDS; 169ed3fe34aSJohn Stultz int runtime = 30; 170ed3fe34aSJohn Stultz struct timespec ts; 171ed3fe34aSJohn Stultz 172ed3fe34aSJohn Stultz /* Process arguments */ 173ed3fe34aSJohn Stultz while ((opt = getopt(argc, argv, "t:c:")) != -1) { 174ed3fe34aSJohn Stultz switch (opt) { 175ed3fe34aSJohn Stultz case 't': 176ed3fe34aSJohn Stultz runtime = atoi(optarg); 177ed3fe34aSJohn Stultz break; 178ed3fe34aSJohn Stultz case 'c': 179ed3fe34aSJohn Stultz userclock = atoi(optarg); 180ed3fe34aSJohn Stultz maxclocks = userclock + 1; 181ed3fe34aSJohn Stultz break; 182ed3fe34aSJohn Stultz default: 183ed3fe34aSJohn Stultz printf("Usage: %s [-t <secs>] [-c <clockid>]\n", argv[0]); 184ed3fe34aSJohn Stultz printf(" -t: Number of seconds to run\n"); 185ed3fe34aSJohn Stultz printf(" -c: clockid to use (default, all clockids)\n"); 186ed3fe34aSJohn Stultz exit(-1); 187ed3fe34aSJohn Stultz } 188ed3fe34aSJohn Stultz } 189ed3fe34aSJohn Stultz 190ed3fe34aSJohn Stultz setbuf(stdout, NULL); 191ed3fe34aSJohn Stultz 192ed3fe34aSJohn Stultz for (clockid = userclock; clockid < maxclocks; clockid++) { 193ed3fe34aSJohn Stultz 194ed3fe34aSJohn Stultz if (clockid == CLOCK_HWSPECIFIC) 195ed3fe34aSJohn Stultz continue; 196ed3fe34aSJohn Stultz 197ed3fe34aSJohn Stultz if (!clock_gettime(clockid, &ts)) { 198ed3fe34aSJohn Stultz printf("Consistent %-30s ", clockstring(clockid)); 199ed3fe34aSJohn Stultz if (consistency_test(clockid, runtime)) 200ed3fe34aSJohn Stultz return ksft_exit_fail(); 201ed3fe34aSJohn Stultz } 202ed3fe34aSJohn Stultz } 203ed3fe34aSJohn Stultz return ksft_exit_pass(); 204ed3fe34aSJohn Stultz } 205