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

selftests/timers: Add set-timer-lat test from timetest suite

Add my set-timer-lat test from the timetest suite. This
test checks the latency from set_timer and reports if
any are unreasonable (>40ms).

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
4e40d0a2 51f91cbd

+213 -1
+4 -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 nsleep-lat raw_skew 5 + bins = posix_timers nanosleep inconsistency-check nsleep-lat raw_skew \ 6 + set-timer-lat 6 7 7 8 all: ${bins} 8 9 ··· 11 10 ./posix_timers 12 11 ./nanosleep 13 12 ./nsleep-lat 13 + ./set-timer-lat 14 14 ./inconsistency-check 15 15 ./raw_skew 16 + 16 17 clean: 17 18 rm -f ${bins}
+209
tools/testing/selftests/timers/set-timer-lat.c
··· 1 + /* set_timer latency test 2 + * John Stultz (john.stultz@linaro.org) 3 + * (C) Copyright Linaro 2014 4 + * Licensed under the GPLv2 5 + * 6 + * This test makes sure the set_timer api is correct 7 + * 8 + * To build: 9 + * $ gcc set-timer-lat.c -o set-timer-lat -lrt 10 + * 11 + * This program is free software: you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation, either version 2 of the License, or 14 + * (at your option) any later version. 15 + * 16 + * This program is distributed in the hope that it will be useful, 17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + * GNU General Public License for more details. 20 + */ 21 + 22 + 23 + #include <stdio.h> 24 + #include <unistd.h> 25 + #include <time.h> 26 + #include <string.h> 27 + #include <signal.h> 28 + #include <stdlib.h> 29 + #include <pthread.h> 30 + #ifdef KTEST 31 + #include "../kselftest.h" 32 + #else 33 + static inline int ksft_exit_pass(void) 34 + { 35 + exit(0); 36 + } 37 + static inline int ksft_exit_fail(void) 38 + { 39 + exit(1); 40 + } 41 + #endif 42 + 43 + #define CLOCK_REALTIME 0 44 + #define CLOCK_MONOTONIC 1 45 + #define CLOCK_PROCESS_CPUTIME_ID 2 46 + #define CLOCK_THREAD_CPUTIME_ID 3 47 + #define CLOCK_MONOTONIC_RAW 4 48 + #define CLOCK_REALTIME_COARSE 5 49 + #define CLOCK_MONOTONIC_COARSE 6 50 + #define CLOCK_BOOTTIME 7 51 + #define CLOCK_REALTIME_ALARM 8 52 + #define CLOCK_BOOTTIME_ALARM 9 53 + #define CLOCK_HWSPECIFIC 10 54 + #define CLOCK_TAI 11 55 + #define NR_CLOCKIDS 12 56 + 57 + 58 + #define NSEC_PER_SEC 1000000000ULL 59 + #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */ 60 + 61 + #define TIMER_SECS 3 62 + int alarmcount; 63 + int clock_id; 64 + struct timespec start_time; 65 + long long max_latency_ns; 66 + 67 + char *clockstring(int clockid) 68 + { 69 + switch (clockid) { 70 + case CLOCK_REALTIME: 71 + return "CLOCK_REALTIME"; 72 + case CLOCK_MONOTONIC: 73 + return "CLOCK_MONOTONIC"; 74 + case CLOCK_PROCESS_CPUTIME_ID: 75 + return "CLOCK_PROCESS_CPUTIME_ID"; 76 + case CLOCK_THREAD_CPUTIME_ID: 77 + return "CLOCK_THREAD_CPUTIME_ID"; 78 + case CLOCK_MONOTONIC_RAW: 79 + return "CLOCK_MONOTONIC_RAW"; 80 + case CLOCK_REALTIME_COARSE: 81 + return "CLOCK_REALTIME_COARSE"; 82 + case CLOCK_MONOTONIC_COARSE: 83 + return "CLOCK_MONOTONIC_COARSE"; 84 + case CLOCK_BOOTTIME: 85 + return "CLOCK_BOOTTIME"; 86 + case CLOCK_REALTIME_ALARM: 87 + return "CLOCK_REALTIME_ALARM"; 88 + case CLOCK_BOOTTIME_ALARM: 89 + return "CLOCK_BOOTTIME_ALARM"; 90 + case CLOCK_TAI: 91 + return "CLOCK_TAI"; 92 + }; 93 + return "UNKNOWN_CLOCKID"; 94 + } 95 + 96 + 97 + long long timespec_sub(struct timespec a, struct timespec b) 98 + { 99 + long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec; 100 + 101 + ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec; 102 + return ret; 103 + } 104 + 105 + 106 + void sigalarm(int signo) 107 + { 108 + long long delta_ns; 109 + struct timespec ts; 110 + 111 + clock_gettime(clock_id, &ts); 112 + alarmcount++; 113 + 114 + delta_ns = timespec_sub(start_time, ts); 115 + delta_ns -= NSEC_PER_SEC * TIMER_SECS * alarmcount; 116 + 117 + if (delta_ns < 0) 118 + printf("%s timer fired early: FAIL\n", clockstring(clock_id)); 119 + 120 + if (delta_ns > max_latency_ns) 121 + max_latency_ns = delta_ns; 122 + } 123 + 124 + int do_timer(int clock_id, int flags) 125 + { 126 + struct sigevent se; 127 + timer_t tm1; 128 + struct itimerspec its1, its2; 129 + int err; 130 + 131 + /* Set up timer: */ 132 + memset(&se, 0, sizeof(se)); 133 + se.sigev_notify = SIGEV_SIGNAL; 134 + se.sigev_signo = SIGRTMAX; 135 + se.sigev_value.sival_int = 0; 136 + 137 + max_latency_ns = 0; 138 + alarmcount = 0; 139 + 140 + err = timer_create(clock_id, &se, &tm1); 141 + if (err) { 142 + printf("%s - timer_create() failed\n", clockstring(clock_id)); 143 + return -1; 144 + } 145 + 146 + clock_gettime(clock_id, &start_time); 147 + if (flags) { 148 + its1.it_value = start_time; 149 + its1.it_value.tv_sec += TIMER_SECS; 150 + } else { 151 + its1.it_value.tv_sec = TIMER_SECS; 152 + its1.it_value.tv_nsec = 0; 153 + } 154 + its1.it_interval.tv_sec = TIMER_SECS; 155 + its1.it_interval.tv_nsec = 0; 156 + 157 + err = timer_settime(tm1, flags, &its1, &its2); 158 + if (err) { 159 + printf("%s - timer_settime() failed\n", clockstring(clock_id)); 160 + return -1; 161 + } 162 + 163 + while (alarmcount < 5) 164 + sleep(1); 165 + 166 + printf("%-22s %s max latency: %10lld ns : ", 167 + clockstring(clock_id), 168 + flags ? "ABSTIME":"RELTIME", 169 + max_latency_ns); 170 + 171 + timer_delete(tm1); 172 + if (max_latency_ns < UNRESONABLE_LATENCY) { 173 + printf("[OK]\n"); 174 + return 0; 175 + } 176 + printf("[FAILED]\n"); 177 + return -1; 178 + } 179 + 180 + int main(void) 181 + { 182 + struct sigaction act; 183 + int signum = SIGRTMAX; 184 + int ret = 0; 185 + 186 + /* Set up signal handler: */ 187 + sigfillset(&act.sa_mask); 188 + act.sa_flags = 0; 189 + act.sa_handler = sigalarm; 190 + sigaction(signum, &act, NULL); 191 + 192 + printf("Setting timers for every %i seconds\n", TIMER_SECS); 193 + for (clock_id = 0; clock_id < NR_CLOCKIDS; clock_id++) { 194 + 195 + if ((clock_id == CLOCK_PROCESS_CPUTIME_ID) || 196 + (clock_id == CLOCK_THREAD_CPUTIME_ID) || 197 + (clock_id == CLOCK_MONOTONIC_RAW) || 198 + (clock_id == CLOCK_REALTIME_COARSE) || 199 + (clock_id == CLOCK_MONOTONIC_COARSE) || 200 + (clock_id == CLOCK_HWSPECIFIC)) 201 + continue; 202 + 203 + ret |= do_timer(clock_id, TIMER_ABSTIME); 204 + ret |= do_timer(clock_id, 0); 205 + } 206 + if (ret) 207 + return ksft_exit_fail(); 208 + return ksft_exit_pass(); 209 + }