Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/timers: Add nsleep-lat test from timetest suite

Adds my nanosleep latency test from the timetest suite.
This checks to make sure we don't see "unreasonable"
latencies (> 40ms) when calling nanosleep.

Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Tested-by: Prarit Bhargava <prarit@redhat.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

John Stultz and committed by
Shuah Khan
c5fffcb2 ed3fe34a

+192 -1
+2 -1
tools/testing/selftests/timers/Makefile
··· 2 2 BUILD_FLAGS = -DKTEST 3 3 CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) 4 4 LDFLAGS += -lrt -lpthread 5 - bins = posix_timers nanosleep inconsistency-check 5 + bins = posix_timers nanosleep inconsistency-check nsleep-lat 6 6 7 7 all: ${bins} 8 8 9 9 run_tests: all 10 10 ./posix_timers 11 11 ./nanosleep 12 + ./nsleep-lat 12 13 ./inconsistency-check 13 14 clean: 14 15 rm -f ${bins}
+190
tools/testing/selftests/timers/nsleep-lat.c
··· 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 30 + static inline int ksft_exit_pass(void) 31 + { 32 + exit(0); 33 + } 34 + static 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 + 61 + char *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 + 90 + struct 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 + 101 + long 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 + 109 + int 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 + 155 + int 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 + }