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 "clock-helpers.h" 32 #include "kselftest.h" 33 34 /* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */ 35 #define CLOCK_HWSPECIFIC 10 36 37 #define CALLS_PER_LOOP 64 38 39 /* returns 1 if a <= b, 0 otherwise */ 40 static inline int in_order(struct timespec a, struct timespec b) 41 { 42 /* use unsigned to avoid false positives on 2038 rollover */ 43 if ((unsigned long)a.tv_sec < (unsigned long)b.tv_sec) 44 return 1; 45 if ((unsigned long)a.tv_sec > (unsigned long)b.tv_sec) 46 return 0; 47 if (a.tv_nsec > b.tv_nsec) 48 return 0; 49 return 1; 50 } 51 52 53 54 int consistency_test(int clock_type, unsigned long seconds) 55 { 56 struct timespec list[CALLS_PER_LOOP]; 57 int i, inconsistent; 58 long now, then; 59 time_t t; 60 char *start_str; 61 62 clock_gettime(clock_type, &list[0]); 63 now = then = list[0].tv_sec; 64 65 /* timestamp start of test */ 66 t = time(0); 67 start_str = ctime(&t); 68 69 while (seconds == -1 || now - then < seconds) { 70 inconsistent = -1; 71 72 /* Fill list */ 73 for (i = 0; i < CALLS_PER_LOOP; i++) 74 clock_gettime(clock_type, &list[i]); 75 76 /* Check for inconsistencies */ 77 for (i = 0; i < CALLS_PER_LOOP - 1; i++) 78 if (!in_order(list[i], list[i+1])) 79 inconsistent = i; 80 81 /* display inconsistency */ 82 if (inconsistent >= 0) { 83 unsigned long long delta; 84 85 ksft_print_msg("\%s\n", start_str); 86 for (i = 0; i < CALLS_PER_LOOP; i++) { 87 if (i == inconsistent) 88 ksft_print_msg("--------------------\n"); 89 ksft_print_msg("%lu:%lu\n", list[i].tv_sec, 90 list[i].tv_nsec); 91 if (i == inconsistent + 1) 92 ksft_print_msg("--------------------\n"); 93 } 94 delta = list[inconsistent].tv_sec * NSEC_PER_SEC; 95 delta += list[inconsistent].tv_nsec; 96 delta -= list[inconsistent+1].tv_sec * NSEC_PER_SEC; 97 delta -= list[inconsistent+1].tv_nsec; 98 ksft_print_msg("Delta: %llu ns\n", delta); 99 fflush(0); 100 /* timestamp inconsistency*/ 101 t = time(0); 102 ksft_print_msg("%s\n", ctime(&t)); 103 return -1; 104 } 105 now = list[0].tv_sec; 106 } 107 return 0; 108 } 109 110 111 int main(int argc, char *argv[]) 112 { 113 int clockid, opt; 114 int userclock = CLOCK_REALTIME; 115 int maxclocks = CLOCK_TAI + 1; 116 int runtime = 10; 117 struct timespec ts; 118 119 /* Process arguments */ 120 while ((opt = getopt(argc, argv, "t:c:")) != -1) { 121 switch (opt) { 122 case 't': 123 runtime = atoi(optarg); 124 break; 125 case 'c': 126 userclock = atoi(optarg); 127 maxclocks = userclock + 1; 128 break; 129 default: 130 printf("Usage: %s [-t <secs>] [-c <clockid>]\n", argv[0]); 131 printf(" -t: Number of seconds to run\n"); 132 printf(" -c: clockid to use (default, all clockids)\n"); 133 exit(-1); 134 } 135 } 136 137 setbuf(stdout, NULL); 138 139 ksft_print_header(); 140 ksft_set_plan(maxclocks - userclock); 141 142 for (clockid = userclock; clockid < maxclocks; clockid++) { 143 144 if (clockid == CLOCK_HWSPECIFIC || clock_gettime(clockid, &ts)) { 145 ksft_test_result_skip("%-31s\n", clock_name(clockid)); 146 continue; 147 } 148 149 if (consistency_test(clockid, runtime)) { 150 ksft_test_result_fail("%-31s\n", clock_name(clockid)); 151 ksft_exit_fail(); 152 } else { 153 ksft_test_result_pass("%-31s\n", clock_name(clockid)); 154 } 155 } 156 ksft_exit_pass(); 157 } 158