linux/tools/testing/selftests/timers/nsleep-lat.c
<<
>>
Prefs
   1/* Measure nanosleep timer latency
   2 *              by: john stultz (john.stultz@linaro.org)
   3 *              (C) Copyright Linaro 2013
   4 *              Licensed under the GPLv2
   5 *
   6 *  To build:
   7 *      $ gcc nsleep-lat.c -o nsleep-lat -lrt
   8 *
   9 *   This program is free software: you can redistribute it and/or modify
  10 *   it under the terms of the GNU General Public License as published by
  11 *   the Free Software Foundation, either version 2 of the License, or
  12 *   (at your option) any later version.
  13 *
  14 *   This program is distributed in the hope that it will be useful,
  15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *   GNU General Public License for more details.
  18 */
  19
  20#include <stdio.h>
  21#include <stdlib.h>
  22#include <time.h>
  23#include <sys/time.h>
  24#include <sys/timex.h>
  25#include <string.h>
  26#include <signal.h>
  27#ifdef KTEST
  28#include "../kselftest.h"
  29#else
  30static inline int ksft_exit_pass(void)
  31{
  32        exit(0);
  33}
  34static inline int ksft_exit_fail(void)
  35{
  36        exit(1);
  37}
  38#endif
  39
  40#define NSEC_PER_SEC 1000000000ULL
  41
  42#define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
  43
  44
  45#define CLOCK_REALTIME                  0
  46#define CLOCK_MONOTONIC                 1
  47#define CLOCK_PROCESS_CPUTIME_ID        2
  48#define CLOCK_THREAD_CPUTIME_ID         3
  49#define CLOCK_MONOTONIC_RAW             4
  50#define CLOCK_REALTIME_COARSE           5
  51#define CLOCK_MONOTONIC_COARSE          6
  52#define CLOCK_BOOTTIME                  7
  53#define CLOCK_REALTIME_ALARM            8
  54#define CLOCK_BOOTTIME_ALARM            9
  55#define CLOCK_HWSPECIFIC                10
  56#define CLOCK_TAI                       11
  57#define NR_CLOCKIDS                     12
  58
  59#define UNSUPPORTED 0xf00f
  60
  61char *clockstring(int clockid)
  62{
  63        switch (clockid) {
  64        case CLOCK_REALTIME:
  65                return "CLOCK_REALTIME";
  66        case CLOCK_MONOTONIC:
  67                return "CLOCK_MONOTONIC";
  68        case CLOCK_PROCESS_CPUTIME_ID:
  69                return "CLOCK_PROCESS_CPUTIME_ID";
  70        case CLOCK_THREAD_CPUTIME_ID:
  71                return "CLOCK_THREAD_CPUTIME_ID";
  72        case CLOCK_MONOTONIC_RAW:
  73                return "CLOCK_MONOTONIC_RAW";
  74        case CLOCK_REALTIME_COARSE:
  75                return "CLOCK_REALTIME_COARSE";
  76        case CLOCK_MONOTONIC_COARSE:
  77                return "CLOCK_MONOTONIC_COARSE";
  78        case CLOCK_BOOTTIME:
  79                return "CLOCK_BOOTTIME";
  80        case CLOCK_REALTIME_ALARM:
  81                return "CLOCK_REALTIME_ALARM";
  82        case CLOCK_BOOTTIME_ALARM:
  83                return "CLOCK_BOOTTIME_ALARM";
  84        case CLOCK_TAI:
  85                return "CLOCK_TAI";
  86        };
  87        return "UNKNOWN_CLOCKID";
  88}
  89
  90struct timespec timespec_add(struct timespec ts, unsigned long long ns)
  91{
  92        ts.tv_nsec += ns;
  93        while (ts.tv_nsec >= NSEC_PER_SEC) {
  94                ts.tv_nsec -= NSEC_PER_SEC;
  95                ts.tv_sec++;
  96        }
  97        return ts;
  98}
  99
 100
 101long long timespec_sub(struct timespec a, struct timespec b)
 102{
 103        long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
 104
 105        ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
 106        return ret;
 107}
 108
 109int nanosleep_lat_test(int clockid, long long ns)
 110{
 111        struct timespec start, end, target;
 112        long long latency = 0;
 113        int i, count;
 114
 115        target.tv_sec = ns/NSEC_PER_SEC;
 116        target.tv_nsec = ns%NSEC_PER_SEC;
 117
 118        if (clock_gettime(clockid, &start))
 119                return UNSUPPORTED;
 120        if (clock_nanosleep(clockid, 0, &target, NULL))
 121                return UNSUPPORTED;
 122
 123        count = 10;
 124
 125        /* First check relative latency */
 126        clock_gettime(clockid, &start);
 127        for (i = 0; i < count; i++)
 128                clock_nanosleep(clockid, 0, &target, NULL);
 129        clock_gettime(clockid, &end);
 130
 131        if (((timespec_sub(start, end)/count)-ns) > UNRESONABLE_LATENCY) {
 132                printf("Large rel latency: %lld ns :", (timespec_sub(start, end)/count)-ns);
 133                return -1;
 134        }
 135
 136        /* Next check absolute latency */
 137        for (i = 0; i < count; i++) {
 138                clock_gettime(clockid, &start);
 139                target = timespec_add(start, ns);
 140                clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL);
 141                clock_gettime(clockid, &end);
 142                latency += timespec_sub(target, end);
 143        }
 144
 145        if (latency/count > UNRESONABLE_LATENCY) {
 146                printf("Large abs latency: %lld ns :", latency/count);
 147                return -1;
 148        }
 149
 150        return 0;
 151}
 152
 153
 154
 155int main(int argc, char **argv)
 156{
 157        long long length;
 158        int clockid, ret;
 159
 160        for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) {
 161
 162                /* Skip cputime clockids since nanosleep won't increment cputime */
 163                if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
 164                                clockid == CLOCK_THREAD_CPUTIME_ID ||
 165                                clockid == CLOCK_HWSPECIFIC)
 166                        continue;
 167
 168                printf("nsleep latency %-26s ", clockstring(clockid));
 169
 170                length = 10;
 171                while (length <= (NSEC_PER_SEC * 10)) {
 172                        ret = nanosleep_lat_test(clockid, length);
 173                        if (ret)
 174                                break;
 175                        length *= 100;
 176
 177                }
 178
 179                if (ret == UNSUPPORTED) {
 180                        printf("[UNSUPPORTED]\n");
 181                        continue;
 182                }
 183                if (ret < 0) {
 184                        printf("[FAILED]\n");
 185                        return ksft_exit_fail();
 186                }
 187                printf("[OK]\n");
 188        }
 189        return ksft_exit_pass();
 190}
 191