root/tools/testing/selftests/timers/nsleep-lat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clockstring
  2. timespec_add
  3. timespec_sub
  4. nanosleep_lat_test
  5. main

   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 #include "../kselftest.h"
  28 
  29 #define NSEC_PER_SEC 1000000000ULL
  30 
  31 #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
  32 
  33 
  34 #define CLOCK_REALTIME                  0
  35 #define CLOCK_MONOTONIC                 1
  36 #define CLOCK_PROCESS_CPUTIME_ID        2
  37 #define CLOCK_THREAD_CPUTIME_ID         3
  38 #define CLOCK_MONOTONIC_RAW             4
  39 #define CLOCK_REALTIME_COARSE           5
  40 #define CLOCK_MONOTONIC_COARSE          6
  41 #define CLOCK_BOOTTIME                  7
  42 #define CLOCK_REALTIME_ALARM            8
  43 #define CLOCK_BOOTTIME_ALARM            9
  44 #define CLOCK_HWSPECIFIC                10
  45 #define CLOCK_TAI                       11
  46 #define NR_CLOCKIDS                     12
  47 
  48 #define UNSUPPORTED 0xf00f
  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 struct timespec timespec_add(struct timespec ts, unsigned long long ns)
  80 {
  81         ts.tv_nsec += ns;
  82         while (ts.tv_nsec >= NSEC_PER_SEC) {
  83                 ts.tv_nsec -= NSEC_PER_SEC;
  84                 ts.tv_sec++;
  85         }
  86         return ts;
  87 }
  88 
  89 
  90 long long timespec_sub(struct timespec a, struct timespec b)
  91 {
  92         long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
  93 
  94         ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
  95         return ret;
  96 }
  97 
  98 int nanosleep_lat_test(int clockid, long long ns)
  99 {
 100         struct timespec start, end, target;
 101         long long latency = 0;
 102         int i, count;
 103 
 104         target.tv_sec = ns/NSEC_PER_SEC;
 105         target.tv_nsec = ns%NSEC_PER_SEC;
 106 
 107         if (clock_gettime(clockid, &start))
 108                 return UNSUPPORTED;
 109         if (clock_nanosleep(clockid, 0, &target, NULL))
 110                 return UNSUPPORTED;
 111 
 112         count = 10;
 113 
 114         /* First check relative latency */
 115         clock_gettime(clockid, &start);
 116         for (i = 0; i < count; i++)
 117                 clock_nanosleep(clockid, 0, &target, NULL);
 118         clock_gettime(clockid, &end);
 119 
 120         if (((timespec_sub(start, end)/count)-ns) > UNRESONABLE_LATENCY) {
 121                 printf("Large rel latency: %lld ns :", (timespec_sub(start, end)/count)-ns);
 122                 return -1;
 123         }
 124 
 125         /* Next check absolute latency */
 126         for (i = 0; i < count; i++) {
 127                 clock_gettime(clockid, &start);
 128                 target = timespec_add(start, ns);
 129                 clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL);
 130                 clock_gettime(clockid, &end);
 131                 latency += timespec_sub(target, end);
 132         }
 133 
 134         if (latency/count > UNRESONABLE_LATENCY) {
 135                 printf("Large abs latency: %lld ns :", latency/count);
 136                 return -1;
 137         }
 138 
 139         return 0;
 140 }
 141 
 142 
 143 
 144 int main(int argc, char **argv)
 145 {
 146         long long length;
 147         int clockid, ret;
 148 
 149         for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) {
 150 
 151                 /* Skip cputime clockids since nanosleep won't increment cputime */
 152                 if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
 153                                 clockid == CLOCK_THREAD_CPUTIME_ID ||
 154                                 clockid == CLOCK_HWSPECIFIC)
 155                         continue;
 156 
 157                 printf("nsleep latency %-26s ", clockstring(clockid));
 158                 fflush(stdout);
 159 
 160                 length = 10;
 161                 while (length <= (NSEC_PER_SEC * 10)) {
 162                         ret = nanosleep_lat_test(clockid, length);
 163                         if (ret)
 164                                 break;
 165                         length *= 100;
 166 
 167                 }
 168 
 169                 if (ret == UNSUPPORTED) {
 170                         printf("[UNSUPPORTED]\n");
 171                         continue;
 172                 }
 173                 if (ret < 0) {
 174                         printf("[FAILED]\n");
 175                         return ksft_exit_fail();
 176                 }
 177                 printf("[OK]\n");
 178         }
 179         return ksft_exit_pass();
 180 }

/* [<][>][^][v][top][bottom][index][help] */