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 printf("\%s\n", start_str); 126 for (i = 0; i < CALLS_PER_LOOP; i++) { 127 if (i == inconsistent) 128 printf("--------------------\n"); 129 printf("%lu:%lu\n", list[i].tv_sec, 130 list[i].tv_nsec); 131 if (i == inconsistent + 1) 132 printf("--------------------\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 printf("Delta: %llu ns\n", delta); 139 fflush(0); 140 /* timestamp inconsistency*/ 141 t = time(0); 142 printf("%s\n", ctime(&t)); 143 printf("[FAILED]\n"); 144 return -1; 145 } 146 now = list[0].tv_sec; 147 } 148 printf("[OK]\n"); 149 return 0; 150 } 151 152 153 int main(int argc, char *argv[]) 154 { 155 int clockid, opt; 156 int userclock = CLOCK_REALTIME; 157 int maxclocks = NR_CLOCKIDS; 158 int runtime = 10; 159 struct timespec ts; 160 161 /* Process arguments */ 162 while ((opt = getopt(argc, argv, "t:c:")) != -1) { 163 switch (opt) { 164 case 't': 165 runtime = atoi(optarg); 166 break; 167 case 'c': 168 userclock = atoi(optarg); 169 maxclocks = userclock + 1; 170 break; 171 default: 172 printf("Usage: %s [-t <secs>] [-c <clockid>]\n", argv[0]); 173 printf(" -t: Number of seconds to run\n"); 174 printf(" -c: clockid to use (default, all clockids)\n"); 175 exit(-1); 176 } 177 } 178 179 setbuf(stdout, NULL); 180 181 for (clockid = userclock; clockid < maxclocks; clockid++) { 182 183 if (clockid == CLOCK_HWSPECIFIC) 184 continue; 185 186 if (!clock_gettime(clockid, &ts)) { 187 printf("Consistent %-30s ", clockstring(clockid)); 188 if (consistency_test(clockid, runtime)) 189 return ksft_exit_fail(); 190 } 191 } 192 return ksft_exit_pass(); 193 } 194