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