1 /* set_timer latency test
2 * John Stultz (john.stultz@linaro.org)
3 * (C) Copyright Linaro 2014
4 * Licensed under the GPLv2
6 * This test makes sure the set_timer api is correct
9 * $ gcc set-timer-lat.c -o set-timer-lat -lrt
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.
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.
31 #include "../kselftest.h"
33 #define CLOCK_REALTIME 0
34 #define CLOCK_MONOTONIC 1
35 #define CLOCK_PROCESS_CPUTIME_ID 2
36 #define CLOCK_THREAD_CPUTIME_ID 3
37 #define CLOCK_MONOTONIC_RAW 4
38 #define CLOCK_REALTIME_COARSE 5
39 #define CLOCK_MONOTONIC_COARSE 6
40 #define CLOCK_BOOTTIME 7
41 #define CLOCK_REALTIME_ALARM 8
42 #define CLOCK_BOOTTIME_ALARM 9
43 #define CLOCK_HWSPECIFIC 10
45 #define NR_CLOCKIDS 12
48 #define NSEC_PER_SEC 1000000000ULL
49 #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
54 struct timespec start_time
;
55 long long max_latency_ns
;
56 int timer_fired_early
;
58 char *clockstring(int clockid
)
62 return "CLOCK_REALTIME";
64 return "CLOCK_MONOTONIC";
65 case CLOCK_PROCESS_CPUTIME_ID
:
66 return "CLOCK_PROCESS_CPUTIME_ID";
67 case CLOCK_THREAD_CPUTIME_ID
:
68 return "CLOCK_THREAD_CPUTIME_ID";
69 case CLOCK_MONOTONIC_RAW
:
70 return "CLOCK_MONOTONIC_RAW";
71 case CLOCK_REALTIME_COARSE
:
72 return "CLOCK_REALTIME_COARSE";
73 case CLOCK_MONOTONIC_COARSE
:
74 return "CLOCK_MONOTONIC_COARSE";
76 return "CLOCK_BOOTTIME";
77 case CLOCK_REALTIME_ALARM
:
78 return "CLOCK_REALTIME_ALARM";
79 case CLOCK_BOOTTIME_ALARM
:
80 return "CLOCK_BOOTTIME_ALARM";
84 return "UNKNOWN_CLOCKID";
88 long long timespec_sub(struct timespec a
, struct timespec b
)
90 long long ret
= NSEC_PER_SEC
* b
.tv_sec
+ b
.tv_nsec
;
92 ret
-= NSEC_PER_SEC
* a
.tv_sec
+ a
.tv_nsec
;
97 void sigalarm(int signo
)
102 clock_gettime(clock_id
, &ts
);
105 delta_ns
= timespec_sub(start_time
, ts
);
106 delta_ns
-= NSEC_PER_SEC
* TIMER_SECS
* alarmcount
;
109 timer_fired_early
= 1;
111 if (delta_ns
> max_latency_ns
)
112 max_latency_ns
= delta_ns
;
115 void describe_timer(int flags
, int interval
)
117 printf("%-22s %s %s ",
118 clockstring(clock_id
),
119 flags
? "ABSTIME":"RELTIME",
120 interval
? "PERIODIC":"ONE-SHOT");
123 int setup_timer(int clock_id
, int flags
, int interval
, timer_t
*tm1
)
126 struct itimerspec its1
, its2
;
130 memset(&se
, 0, sizeof(se
));
131 se
.sigev_notify
= SIGEV_SIGNAL
;
132 se
.sigev_signo
= SIGRTMAX
;
133 se
.sigev_value
.sival_int
= 0;
137 timer_fired_early
= 0;
139 err
= timer_create(clock_id
, &se
, tm1
);
141 if ((clock_id
== CLOCK_REALTIME_ALARM
) ||
142 (clock_id
== CLOCK_BOOTTIME_ALARM
)) {
143 printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n",
144 clockstring(clock_id
),
145 flags
? "ABSTIME":"RELTIME");
146 /* Indicate timer isn't set, so caller doesn't wait */
149 printf("%s - timer_create() failed\n", clockstring(clock_id
));
153 clock_gettime(clock_id
, &start_time
);
155 its1
.it_value
= start_time
;
156 its1
.it_value
.tv_sec
+= TIMER_SECS
;
158 its1
.it_value
.tv_sec
= TIMER_SECS
;
159 its1
.it_value
.tv_nsec
= 0;
161 its1
.it_interval
.tv_sec
= interval
;
162 its1
.it_interval
.tv_nsec
= 0;
164 err
= timer_settime(*tm1
, flags
, &its1
, &its2
);
166 printf("%s - timer_settime() failed\n", clockstring(clock_id
));
173 int check_timer_latency(int flags
, int interval
)
177 describe_timer(flags
, interval
);
178 printf("timer fired early: %7d : ", timer_fired_early
);
179 if (!timer_fired_early
) {
182 printf("[FAILED]\n");
186 describe_timer(flags
, interval
);
187 printf("max latency: %10lld ns : ", max_latency_ns
);
189 if (max_latency_ns
< UNRESONABLE_LATENCY
) {
192 printf("[FAILED]\n");
198 int check_alarmcount(int flags
, int interval
)
200 describe_timer(flags
, interval
);
201 printf("count: %19d : ", alarmcount
);
202 if (alarmcount
== 1) {
206 printf("[FAILED]\n");
210 int do_timer(int clock_id
, int flags
)
213 const int interval
= TIMER_SECS
;
216 err
= setup_timer(clock_id
, flags
, interval
, &tm1
);
217 /* Unsupported case - return 0 to not fail the test */
219 return err
== 1 ? 0 : err
;
221 while (alarmcount
< 5)
225 return check_timer_latency(flags
, interval
);
228 int do_timer_oneshot(int clock_id
, int flags
)
231 const int interval
= 0;
232 struct timeval timeout
;
235 err
= setup_timer(clock_id
, flags
, interval
, &tm1
);
236 /* Unsupported case - return 0 to not fail the test */
238 return err
== 1 ? 0 : err
;
240 memset(&timeout
, 0, sizeof(timeout
));
243 err
= select(0, NULL
, NULL
, NULL
, &timeout
);
244 } while (err
== -1 && errno
== EINTR
);
247 err
= check_timer_latency(flags
, interval
);
248 err
|= check_alarmcount(flags
, interval
);
254 struct sigaction act
;
255 int signum
= SIGRTMAX
;
258 /* Set up signal handler: */
259 sigfillset(&act
.sa_mask
);
261 act
.sa_handler
= sigalarm
;
262 sigaction(signum
, &act
, NULL
);
264 printf("Setting timers for every %i seconds\n", TIMER_SECS
);
265 for (clock_id
= 0; clock_id
< NR_CLOCKIDS
; clock_id
++) {
267 if ((clock_id
== CLOCK_PROCESS_CPUTIME_ID
) ||
268 (clock_id
== CLOCK_THREAD_CPUTIME_ID
) ||
269 (clock_id
== CLOCK_MONOTONIC_RAW
) ||
270 (clock_id
== CLOCK_REALTIME_COARSE
) ||
271 (clock_id
== CLOCK_MONOTONIC_COARSE
) ||
272 (clock_id
== CLOCK_HWSPECIFIC
))
275 ret
|= do_timer(clock_id
, TIMER_ABSTIME
);
276 ret
|= do_timer(clock_id
, 0);
277 ret
|= do_timer_oneshot(clock_id
, TIMER_ABSTIME
);
278 ret
|= do_timer_oneshot(clock_id
, 0);
281 return ksft_exit_fail();
282 return ksft_exit_pass();