2015-03-12 03:40:00 +03:00
/* Time inconsistency check test
* by : john stultz ( johnstul @ us . ibm . com )
* ( C ) Copyright IBM 2003 , 2004 , 2005 , 2012
* ( C ) Copyright Linaro Limited 2015
* Licensed under the GPLv2
*
* To build :
* $ gcc inconsistency - check . c - o inconsistency - check - lrt
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <time.h>
# include <sys/time.h>
# include <sys/timex.h>
# include <string.h>
# include <signal.h>
# include "../kselftest.h"
# define CALLS_PER_LOOP 64
# define NSEC_PER_SEC 1000000000ULL
# define CLOCK_REALTIME 0
# define CLOCK_MONOTONIC 1
# define CLOCK_PROCESS_CPUTIME_ID 2
# define CLOCK_THREAD_CPUTIME_ID 3
# define CLOCK_MONOTONIC_RAW 4
# define CLOCK_REALTIME_COARSE 5
# define CLOCK_MONOTONIC_COARSE 6
# define CLOCK_BOOTTIME 7
# define CLOCK_REALTIME_ALARM 8
# define CLOCK_BOOTTIME_ALARM 9
# define CLOCK_HWSPECIFIC 10
# define CLOCK_TAI 11
# define NR_CLOCKIDS 12
char * clockstring ( int clockid )
{
switch ( clockid ) {
case CLOCK_REALTIME :
return " CLOCK_REALTIME " ;
case CLOCK_MONOTONIC :
return " CLOCK_MONOTONIC " ;
case CLOCK_PROCESS_CPUTIME_ID :
return " CLOCK_PROCESS_CPUTIME_ID " ;
case CLOCK_THREAD_CPUTIME_ID :
return " CLOCK_THREAD_CPUTIME_ID " ;
case CLOCK_MONOTONIC_RAW :
return " CLOCK_MONOTONIC_RAW " ;
case CLOCK_REALTIME_COARSE :
return " CLOCK_REALTIME_COARSE " ;
case CLOCK_MONOTONIC_COARSE :
return " CLOCK_MONOTONIC_COARSE " ;
case CLOCK_BOOTTIME :
return " CLOCK_BOOTTIME " ;
case CLOCK_REALTIME_ALARM :
return " CLOCK_REALTIME_ALARM " ;
case CLOCK_BOOTTIME_ALARM :
return " CLOCK_BOOTTIME_ALARM " ;
case CLOCK_TAI :
return " CLOCK_TAI " ;
2021-11-05 04:42:08 +03:00
}
2015-03-12 03:40:00 +03:00
return " UNKNOWN_CLOCKID " ;
}
/* returns 1 if a <= b, 0 otherwise */
static inline int in_order ( struct timespec a , struct timespec b )
{
/* use unsigned to avoid false positives on 2038 rollover */
if ( ( unsigned long ) a . tv_sec < ( unsigned long ) b . tv_sec )
return 1 ;
if ( ( unsigned long ) a . tv_sec > ( unsigned long ) b . tv_sec )
return 0 ;
if ( a . tv_nsec > b . tv_nsec )
return 0 ;
return 1 ;
}
int consistency_test ( int clock_type , unsigned long seconds )
{
struct timespec list [ CALLS_PER_LOOP ] ;
int i , inconsistent ;
long now , then ;
time_t t ;
char * start_str ;
clock_gettime ( clock_type , & list [ 0 ] ) ;
now = then = list [ 0 ] . tv_sec ;
/* timestamp start of test */
t = time ( 0 ) ;
start_str = ctime ( & t ) ;
while ( seconds = = - 1 | | now - then < seconds ) {
2017-06-13 13:57:07 +03:00
inconsistent = - 1 ;
2015-03-12 03:40:00 +03:00
/* Fill list */
for ( i = 0 ; i < CALLS_PER_LOOP ; i + + )
clock_gettime ( clock_type , & list [ i ] ) ;
/* Check for inconsistencies */
for ( i = 0 ; i < CALLS_PER_LOOP - 1 ; i + + )
if ( ! in_order ( list [ i ] , list [ i + 1 ] ) )
inconsistent = i ;
/* display inconsistency */
2017-06-13 13:57:07 +03:00
if ( inconsistent > = 0 ) {
2015-03-12 03:40:00 +03:00
unsigned long long delta ;
2022-07-13 23:46:16 +03:00
ksft_print_msg ( " \ %s \n " , start_str ) ;
2015-03-12 03:40:00 +03:00
for ( i = 0 ; i < CALLS_PER_LOOP ; i + + ) {
if ( i = = inconsistent )
2022-07-13 23:46:16 +03:00
ksft_print_msg ( " -------------------- \n " ) ;
ksft_print_msg ( " %lu:%lu \n " , list [ i ] . tv_sec ,
2015-03-12 03:40:00 +03:00
list [ i ] . tv_nsec ) ;
if ( i = = inconsistent + 1 )
2022-07-13 23:46:16 +03:00
ksft_print_msg ( " -------------------- \n " ) ;
2015-03-12 03:40:00 +03:00
}
delta = list [ inconsistent ] . tv_sec * NSEC_PER_SEC ;
delta + = list [ inconsistent ] . tv_nsec ;
delta - = list [ inconsistent + 1 ] . tv_sec * NSEC_PER_SEC ;
delta - = list [ inconsistent + 1 ] . tv_nsec ;
2022-07-13 23:46:16 +03:00
ksft_print_msg ( " Delta: %llu ns \n " , delta ) ;
2015-03-12 03:40:00 +03:00
fflush ( 0 ) ;
/* timestamp inconsistency*/
t = time ( 0 ) ;
2022-07-13 23:46:16 +03:00
ksft_print_msg ( " %s \n " , ctime ( & t ) ) ;
2015-03-12 03:40:00 +03:00
return - 1 ;
}
now = list [ 0 ] . tv_sec ;
}
return 0 ;
}
int main ( int argc , char * argv [ ] )
{
int clockid , opt ;
int userclock = CLOCK_REALTIME ;
int maxclocks = NR_CLOCKIDS ;
2015-03-26 02:44:33 +03:00
int runtime = 10 ;
2015-03-12 03:40:00 +03:00
struct timespec ts ;
/* Process arguments */
while ( ( opt = getopt ( argc , argv , " t:c: " ) ) ! = - 1 ) {
switch ( opt ) {
case ' t ' :
runtime = atoi ( optarg ) ;
break ;
case ' c ' :
userclock = atoi ( optarg ) ;
maxclocks = userclock + 1 ;
break ;
default :
printf ( " Usage: %s [-t <secs>] [-c <clockid>] \n " , argv [ 0 ] ) ;
printf ( " -t: Number of seconds to run \n " ) ;
printf ( " -c: clockid to use (default, all clockids) \n " ) ;
exit ( - 1 ) ;
}
}
setbuf ( stdout , NULL ) ;
2022-07-13 23:46:16 +03:00
ksft_print_header ( ) ;
ksft_set_plan ( maxclocks - userclock ) ;
2015-03-12 03:40:00 +03:00
for ( clockid = userclock ; clockid < maxclocks ; clockid + + ) {
2022-07-13 23:46:16 +03:00
if ( clockid = = CLOCK_HWSPECIFIC | | clock_gettime ( clockid , & ts ) ) {
ksft_test_result_skip ( " %-31s \n " , clockstring ( clockid ) ) ;
2015-03-12 03:40:00 +03:00
continue ;
2022-07-13 23:46:16 +03:00
}
2015-03-12 03:40:00 +03:00
2022-07-13 23:46:16 +03:00
if ( consistency_test ( clockid , runtime ) ) {
ksft_test_result_fail ( " %-31s \n " , clockstring ( clockid ) ) ;
ksft_exit_fail ( ) ;
} else {
ksft_test_result_pass ( " %-31s \n " , clockstring ( clockid ) ) ;
2015-03-12 03:40:00 +03:00
}
}
2022-07-13 23:46:16 +03:00
ksft_exit_pass ( ) ;
2015-03-12 03:40:00 +03:00
}