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 #include "../kselftest.h" 32ed3fe34aSJohn Stultz 33ed3fe34aSJohn Stultz #define CALLS_PER_LOOP 64 34ed3fe34aSJohn Stultz #define NSEC_PER_SEC 1000000000ULL 35ed3fe34aSJohn Stultz 36ed3fe34aSJohn Stultz #define CLOCK_REALTIME 0 37ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC 1 38ed3fe34aSJohn Stultz #define CLOCK_PROCESS_CPUTIME_ID 2 39ed3fe34aSJohn Stultz #define CLOCK_THREAD_CPUTIME_ID 3 40ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC_RAW 4 41ed3fe34aSJohn Stultz #define CLOCK_REALTIME_COARSE 5 42ed3fe34aSJohn Stultz #define CLOCK_MONOTONIC_COARSE 6 43ed3fe34aSJohn Stultz #define CLOCK_BOOTTIME 7 44ed3fe34aSJohn Stultz #define CLOCK_REALTIME_ALARM 8 45ed3fe34aSJohn Stultz #define CLOCK_BOOTTIME_ALARM 9 46ed3fe34aSJohn Stultz #define CLOCK_HWSPECIFIC 10 47ed3fe34aSJohn Stultz #define CLOCK_TAI 11 48ed3fe34aSJohn Stultz #define NR_CLOCKIDS 12 49ed3fe34aSJohn Stultz 50ed3fe34aSJohn Stultz char *clockstring(int clockid) 51ed3fe34aSJohn Stultz { 52ed3fe34aSJohn Stultz switch (clockid) { 53ed3fe34aSJohn Stultz case CLOCK_REALTIME: 54ed3fe34aSJohn Stultz return "CLOCK_REALTIME"; 55ed3fe34aSJohn Stultz case CLOCK_MONOTONIC: 56ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC"; 57ed3fe34aSJohn Stultz case CLOCK_PROCESS_CPUTIME_ID: 58ed3fe34aSJohn Stultz return "CLOCK_PROCESS_CPUTIME_ID"; 59ed3fe34aSJohn Stultz case CLOCK_THREAD_CPUTIME_ID: 60ed3fe34aSJohn Stultz return "CLOCK_THREAD_CPUTIME_ID"; 61ed3fe34aSJohn Stultz case CLOCK_MONOTONIC_RAW: 62ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC_RAW"; 63ed3fe34aSJohn Stultz case CLOCK_REALTIME_COARSE: 64ed3fe34aSJohn Stultz return "CLOCK_REALTIME_COARSE"; 65ed3fe34aSJohn Stultz case CLOCK_MONOTONIC_COARSE: 66ed3fe34aSJohn Stultz return "CLOCK_MONOTONIC_COARSE"; 67ed3fe34aSJohn Stultz case CLOCK_BOOTTIME: 68ed3fe34aSJohn Stultz return "CLOCK_BOOTTIME"; 69ed3fe34aSJohn Stultz case CLOCK_REALTIME_ALARM: 70ed3fe34aSJohn Stultz return "CLOCK_REALTIME_ALARM"; 71ed3fe34aSJohn Stultz case CLOCK_BOOTTIME_ALARM: 72ed3fe34aSJohn Stultz return "CLOCK_BOOTTIME_ALARM"; 73ed3fe34aSJohn Stultz case CLOCK_TAI: 74ed3fe34aSJohn Stultz return "CLOCK_TAI"; 75*7ace3e9aSZhang Mingyu } 76ed3fe34aSJohn Stultz return "UNKNOWN_CLOCKID"; 77ed3fe34aSJohn Stultz } 78ed3fe34aSJohn Stultz 79ed3fe34aSJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 80ed3fe34aSJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 81ed3fe34aSJohn Stultz { 82ed3fe34aSJohn Stultz /* use unsigned to avoid false positives on 2038 rollover */ 83ed3fe34aSJohn Stultz if ((unsigned long)a.tv_sec < (unsigned long)b.tv_sec) 84ed3fe34aSJohn Stultz return 1; 85ed3fe34aSJohn Stultz if ((unsigned long)a.tv_sec > (unsigned long)b.tv_sec) 86ed3fe34aSJohn Stultz return 0; 87ed3fe34aSJohn Stultz if (a.tv_nsec > b.tv_nsec) 88ed3fe34aSJohn Stultz return 0; 89ed3fe34aSJohn Stultz return 1; 90ed3fe34aSJohn Stultz } 91ed3fe34aSJohn Stultz 92ed3fe34aSJohn Stultz 93ed3fe34aSJohn Stultz 94ed3fe34aSJohn Stultz int consistency_test(int clock_type, unsigned long seconds) 95ed3fe34aSJohn Stultz { 96ed3fe34aSJohn Stultz struct timespec list[CALLS_PER_LOOP]; 97ed3fe34aSJohn Stultz int i, inconsistent; 98ed3fe34aSJohn Stultz long now, then; 99ed3fe34aSJohn Stultz time_t t; 100ed3fe34aSJohn Stultz char *start_str; 101ed3fe34aSJohn Stultz 102ed3fe34aSJohn Stultz clock_gettime(clock_type, &list[0]); 103ed3fe34aSJohn Stultz now = then = list[0].tv_sec; 104ed3fe34aSJohn Stultz 105ed3fe34aSJohn Stultz /* timestamp start of test */ 106ed3fe34aSJohn Stultz t = time(0); 107ed3fe34aSJohn Stultz start_str = ctime(&t); 108ed3fe34aSJohn Stultz 109ed3fe34aSJohn Stultz while (seconds == -1 || now - then < seconds) { 1107a5de551SMiroslav Lichvar inconsistent = -1; 111ed3fe34aSJohn Stultz 112ed3fe34aSJohn Stultz /* Fill list */ 113ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP; i++) 114ed3fe34aSJohn Stultz clock_gettime(clock_type, &list[i]); 115ed3fe34aSJohn Stultz 116ed3fe34aSJohn Stultz /* Check for inconsistencies */ 117ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP - 1; i++) 118ed3fe34aSJohn Stultz if (!in_order(list[i], list[i+1])) 119ed3fe34aSJohn Stultz inconsistent = i; 120ed3fe34aSJohn Stultz 121ed3fe34aSJohn Stultz /* display inconsistency */ 1227a5de551SMiroslav Lichvar if (inconsistent >= 0) { 123ed3fe34aSJohn Stultz unsigned long long delta; 124ed3fe34aSJohn Stultz 125ed3fe34aSJohn Stultz printf("\%s\n", start_str); 126ed3fe34aSJohn Stultz for (i = 0; i < CALLS_PER_LOOP; i++) { 127ed3fe34aSJohn Stultz if (i == inconsistent) 128ed3fe34aSJohn Stultz printf("--------------------\n"); 129ed3fe34aSJohn Stultz printf("%lu:%lu\n", list[i].tv_sec, 130ed3fe34aSJohn Stultz list[i].tv_nsec); 131ed3fe34aSJohn Stultz if (i == inconsistent + 1) 132ed3fe34aSJohn Stultz printf("--------------------\n"); 133ed3fe34aSJohn Stultz } 134ed3fe34aSJohn Stultz delta = list[inconsistent].tv_sec * NSEC_PER_SEC; 135ed3fe34aSJohn Stultz delta += list[inconsistent].tv_nsec; 136ed3fe34aSJohn Stultz delta -= list[inconsistent+1].tv_sec * NSEC_PER_SEC; 137ed3fe34aSJohn Stultz delta -= list[inconsistent+1].tv_nsec; 138ed3fe34aSJohn Stultz printf("Delta: %llu ns\n", delta); 139ed3fe34aSJohn Stultz fflush(0); 140ed3fe34aSJohn Stultz /* timestamp inconsistency*/ 141ed3fe34aSJohn Stultz t = time(0); 142ed3fe34aSJohn Stultz printf("%s\n", ctime(&t)); 143ed3fe34aSJohn Stultz printf("[FAILED]\n"); 144ed3fe34aSJohn Stultz return -1; 145ed3fe34aSJohn Stultz } 146ed3fe34aSJohn Stultz now = list[0].tv_sec; 147ed3fe34aSJohn Stultz } 148ed3fe34aSJohn Stultz printf("[OK]\n"); 149ed3fe34aSJohn Stultz return 0; 150ed3fe34aSJohn Stultz } 151ed3fe34aSJohn Stultz 152ed3fe34aSJohn Stultz 153ed3fe34aSJohn Stultz int main(int argc, char *argv[]) 154ed3fe34aSJohn Stultz { 155ed3fe34aSJohn Stultz int clockid, opt; 156ed3fe34aSJohn Stultz int userclock = CLOCK_REALTIME; 157ed3fe34aSJohn Stultz int maxclocks = NR_CLOCKIDS; 158e48f284dSJohn Stultz int runtime = 10; 159ed3fe34aSJohn Stultz struct timespec ts; 160ed3fe34aSJohn Stultz 161ed3fe34aSJohn Stultz /* Process arguments */ 162ed3fe34aSJohn Stultz while ((opt = getopt(argc, argv, "t:c:")) != -1) { 163ed3fe34aSJohn Stultz switch (opt) { 164ed3fe34aSJohn Stultz case 't': 165ed3fe34aSJohn Stultz runtime = atoi(optarg); 166ed3fe34aSJohn Stultz break; 167ed3fe34aSJohn Stultz case 'c': 168ed3fe34aSJohn Stultz userclock = atoi(optarg); 169ed3fe34aSJohn Stultz maxclocks = userclock + 1; 170ed3fe34aSJohn Stultz break; 171ed3fe34aSJohn Stultz default: 172ed3fe34aSJohn Stultz printf("Usage: %s [-t <secs>] [-c <clockid>]\n", argv[0]); 173ed3fe34aSJohn Stultz printf(" -t: Number of seconds to run\n"); 174ed3fe34aSJohn Stultz printf(" -c: clockid to use (default, all clockids)\n"); 175ed3fe34aSJohn Stultz exit(-1); 176ed3fe34aSJohn Stultz } 177ed3fe34aSJohn Stultz } 178ed3fe34aSJohn Stultz 179ed3fe34aSJohn Stultz setbuf(stdout, NULL); 180ed3fe34aSJohn Stultz 181ed3fe34aSJohn Stultz for (clockid = userclock; clockid < maxclocks; clockid++) { 182ed3fe34aSJohn Stultz 183ed3fe34aSJohn Stultz if (clockid == CLOCK_HWSPECIFIC) 184ed3fe34aSJohn Stultz continue; 185ed3fe34aSJohn Stultz 186ed3fe34aSJohn Stultz if (!clock_gettime(clockid, &ts)) { 187ed3fe34aSJohn Stultz printf("Consistent %-30s ", clockstring(clockid)); 188ed3fe34aSJohn Stultz if (consistency_test(clockid, runtime)) 189ed3fe34aSJohn Stultz return ksft_exit_fail(); 190ed3fe34aSJohn Stultz } 191ed3fe34aSJohn Stultz } 192ed3fe34aSJohn Stultz return ksft_exit_pass(); 193ed3fe34aSJohn Stultz } 194