]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/testing/selftests/timers/posix_timers.c
Merge remote-tracking branch 'hid/for-next'
[karo-tx-linux.git] / tools / testing / selftests / timers / posix_timers.c
1 /*
2  * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
3  *
4  * Licensed under the terms of the GNU GPL License version 2
5  *
6  * Selftests for a few posix timers interface.
7  *
8  * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
9  */
10
11 #include <sys/time.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <unistd.h>
15 #include <time.h>
16 #include <pthread.h>
17
18 #define DELAY 2
19 #define USECS_PER_SEC 1000000
20
21 static volatile int done;
22
23 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
24 static void user_loop(void)
25 {
26         while (!done);
27 }
28
29 /*
30  * Try to spend as much time as possible in kernelspace
31  * to elapse ITIMER_PROF.
32  */
33 static void kernel_loop(void)
34 {
35         void *addr = sbrk(0);
36
37         while (!done) {
38                 brk(addr + 4096);
39                 brk(addr);
40         }
41 }
42
43 /*
44  * Sleep until ITIMER_REAL expiration.
45  */
46 static void idle_loop(void)
47 {
48         pause();
49 }
50
51 static void sig_handler(int nr)
52 {
53         done = 1;
54 }
55
56 /*
57  * Check the expected timer expiration matches the GTOD elapsed delta since
58  * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
59  */
60 static int check_diff(struct timeval start, struct timeval end)
61 {
62         long long diff;
63
64         diff = end.tv_usec - start.tv_usec;
65         diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
66
67         if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
68                 printf("Diff too high: %lld..", diff);
69                 return -1;
70         }
71
72         return 0;
73 }
74
75 static int check_itimer(int which)
76 {
77         int err;
78         struct timeval start, end;
79         struct itimerval val = {
80                 .it_value.tv_sec = DELAY,
81         };
82
83         printf("Check itimer ");
84
85         if (which == ITIMER_VIRTUAL)
86                 printf("virtual... ");
87         else if (which == ITIMER_PROF)
88                 printf("prof... ");
89         else if (which == ITIMER_REAL)
90                 printf("real... ");
91
92         fflush(stdout);
93
94         done = 0;
95
96         if (which == ITIMER_VIRTUAL)
97                 signal(SIGVTALRM, sig_handler);
98         else if (which == ITIMER_PROF)
99                 signal(SIGPROF, sig_handler);
100         else if (which == ITIMER_REAL)
101                 signal(SIGALRM, sig_handler);
102
103         err = gettimeofday(&start, NULL);
104         if (err < 0) {
105                 perror("Can't call gettimeofday()\n");
106                 return -1;
107         }
108
109         err = setitimer(which, &val, NULL);
110         if (err < 0) {
111                 perror("Can't set timer\n");
112                 return -1;
113         }
114
115         if (which == ITIMER_VIRTUAL)
116                 user_loop();
117         else if (which == ITIMER_PROF)
118                 kernel_loop();
119         else if (which == ITIMER_REAL)
120                 idle_loop();
121
122         gettimeofday(&end, NULL);
123         if (err < 0) {
124                 perror("Can't call gettimeofday()\n");
125                 return -1;
126         }
127
128         if (!check_diff(start, end))
129                 printf("[OK]\n");
130         else
131                 printf("[FAIL]\n");
132
133         return 0;
134 }
135
136 static int check_timer_create(int which)
137 {
138         int err;
139         timer_t id;
140         struct timeval start, end;
141         struct itimerspec val = {
142                 .it_value.tv_sec = DELAY,
143         };
144
145         printf("Check timer_create() ");
146         if (which == CLOCK_THREAD_CPUTIME_ID) {
147                 printf("per thread... ");
148         } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
149                 printf("per process... ");
150         }
151         fflush(stdout);
152
153         done = 0;
154         err = timer_create(which, NULL, &id);
155         if (err < 0) {
156                 perror("Can't create timer\n");
157                 return -1;
158         }
159         signal(SIGALRM, sig_handler);
160
161         err = gettimeofday(&start, NULL);
162         if (err < 0) {
163                 perror("Can't call gettimeofday()\n");
164                 return -1;
165         }
166
167         err = timer_settime(id, 0, &val, NULL);
168         if (err < 0) {
169                 perror("Can't set timer\n");
170                 return -1;
171         }
172
173         user_loop();
174
175         gettimeofday(&end, NULL);
176         if (err < 0) {
177                 perror("Can't call gettimeofday()\n");
178                 return -1;
179         }
180
181         if (!check_diff(start, end))
182                 printf("[OK]\n");
183         else
184                 printf("[FAIL]\n");
185
186         return 0;
187 }
188
189 int main(int argc, char **argv)
190 {
191         int err;
192
193         printf("Testing posix timers. False negative may happen on CPU execution \n");
194         printf("based timers if other threads run on the CPU...\n");
195
196         if (check_itimer(ITIMER_VIRTUAL) < 0)
197                 return -1;
198
199         if (check_itimer(ITIMER_PROF) < 0)
200                 return -1;
201
202         if (check_itimer(ITIMER_REAL) < 0)
203                 return -1;
204
205         if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
206                 return -1;
207
208         /*
209          * It's unfortunately hard to reliably test a timer expiration
210          * on parallel multithread cputime. We could arm it to expire
211          * on DELAY * nr_threads, with nr_threads busy looping, then wait
212          * the normal DELAY since the time is elapsing nr_threads faster.
213          * But for that we need to ensure we have real physical free CPUs
214          * to ensure true parallelism. So test only one thread until we
215          * find a better solution.
216          */
217         if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
218                 return -1;
219
220         return 0;
221 }