linux/tools/testing/selftests/timers/inconsistency-check.c
<<
>>
Prefs
   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
  50char *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 */
  80static 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
  94int 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
 153int 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