]> git.ipfire.org Git - thirdparty/glibc.git/blame - rt/tst-cpuclock2.c
Installed-header hygiene (BZ#20366): time.h types.
[thirdparty/glibc.git] / rt / tst-cpuclock2.c
CommitLineData
84060bad 1/* Test program for process and thread CPU clocks.
f7a9f785 2 Copyright (C) 2005-2016 Free Software Foundation, Inc.
84060bad
RM
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
84060bad
RM
18
19#include <unistd.h>
5d619de4 20#include <stdint.h>
84060bad
RM
21
22#if (_POSIX_THREADS - 0) <= 0
23
24# define TEST_FUNCTION 0
25
26#else
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <time.h>
31#include <fcntl.h>
32#include <string.h>
33#include <errno.h>
34#include <pthread.h>
35
36static pthread_barrier_t barrier;
37
38/* This function is intended to rack up both user and system time. */
39static void *
40chew_cpu (void *arg)
41{
42 pthread_barrier_wait (&barrier);
43
44 while (1)
45 {
46 static volatile char buf[4096];
47 for (int i = 0; i < 100; ++i)
48 for (size_t j = 0; j < sizeof buf; ++j)
49 buf[j] = 0xaa;
50 int nullfd = open ("/dev/null", O_WRONLY);
51 for (int i = 0; i < 100; ++i)
52 for (size_t j = 0; j < sizeof buf; ++j)
53 buf[j] = 0xbb;
54 write (nullfd, (char *) buf, sizeof buf);
55 close (nullfd);
56 }
57
58 return NULL;
59}
60
61static unsigned long long int
62tsdiff (const struct timespec *before, const struct timespec *after)
63{
64 struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
65 .tv_nsec = after->tv_nsec - before->tv_nsec };
66 while (diff.tv_nsec < 0)
67 {
68 --diff.tv_sec;
69 diff.tv_nsec += 1000000000;
70 }
71 return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
72}
73
74static unsigned long long int
75test_nanosleep (clockid_t clock, const char *which,
76 const struct timespec *before, int *bad)
77{
78 const struct timespec sleeptime = { .tv_nsec = 100000000 };
79 int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
80 if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
81 {
82 printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
83 which, strerror (e));
84 return 0;
85 }
86 if (e != 0)
87 {
88 printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
89 *bad = 1;
90 return 0;
91 }
92
93 struct timespec after;
94 if (clock_gettime (clock, &after) < 0)
95 {
96 printf ("clock_gettime on %s CPU clock %lx => %s\n",
97 which, (unsigned long int) clock, strerror (errno));
98 *bad = 1;
99 return 0;
100 }
101
102 unsigned long long int diff = tsdiff (before, &after);
103 if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
104 {
105 printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
106 which, diff);
107 *bad = 1;
108 return diff;
109 }
110
111 struct timespec sleeptimeabs = sleeptime;
112 sleeptimeabs.tv_sec += after.tv_sec;
113 sleeptimeabs.tv_nsec += after.tv_nsec;
82d86f28 114 while (sleeptimeabs.tv_nsec >= 1000000000)
84060bad
RM
115 {
116 ++sleeptimeabs.tv_sec;
117 sleeptimeabs.tv_nsec -= 1000000000;
118 }
119 e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
120 if (e != 0)
121 {
122 printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
123 which, strerror (e));
124 *bad = 1;
125 return diff;
126 }
127
128 struct timespec afterabs;
129 if (clock_gettime (clock, &afterabs) < 0)
130 {
131 printf ("clock_gettime on %s CPU clock %lx => %s\n",
132 which, (unsigned long int) clock, strerror (errno));
133 *bad = 1;
134 return diff;
135 }
136
137 unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
138 if (sleepdiff > sleeptime.tv_nsec)
139 {
140 printf ("\
141absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
142 which, sleepdiff);
143 *bad = 1;
144 }
145
146 unsigned long long int diffabs = tsdiff (&after, &afterabs);
147 if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
148 {
149 printf ("\
150absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
151 which, diffabs);
152 *bad = 1;
153 }
154
155 return diff + diffabs;
156}
157
158
159
160static int
161do_test (void)
162{
163 int result = 0;
164 clockid_t process_clock, th_clock, my_thread_clock;
165 int e;
166 pthread_t th;
167
168 e = clock_getcpuclockid (0, &process_clock);
169 if (e != 0)
170 {
171 printf ("clock_getcpuclockid on self => %s\n", strerror (e));
172 return 1;
173 }
174
175 e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
176 if (e != 0)
177 {
178 printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
179 return 1;
180 }
181
182 /* This is a kludge. This test fails if the semantics of thread and
183 process clocks are wrong. The old code using hp-timing without kernel
184 support has bogus semantics if there are context switches. We don't
185 fail to report failure when the proper functionality is not available
186 in the kernel. It so happens that Linux kernels without correct CPU
187 clock support also lack CPU timer support, so we use use that to guess
188 that we are using the bogus code and not test it. */
189 timer_t t;
190 if (timer_create (my_thread_clock, NULL, &t) != 0)
191 {
192 printf ("timer_create: %m\n");
193 puts ("No support for CPU clocks with good semantics, skipping test");
194 return 0;
195 }
196 timer_delete (t);
197
198
199 pthread_barrier_init (&barrier, NULL, 2);
200
201 e = pthread_create (&th, NULL, chew_cpu, NULL);
202 if (e != 0)
203 {
204 printf ("pthread_create: %s\n", strerror (e));
205 return 1;
206 }
207
208 e = pthread_getcpuclockid (th, &th_clock);
209 if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
210 {
211 puts ("pthread_getcpuclockid does not support other threads");
212 return 1;
213 }
214
215 pthread_barrier_wait (&barrier);
216
217 struct timespec res;
218 if (clock_getres (th_clock, &res) < 0)
219 {
fb779be7 220 printf ("clock_getres on live thread clock %lx => %s\n",
84060bad
RM
221 (unsigned long int) th_clock, strerror (errno));
222 result = 1;
223 return 1;
224 }
5d619de4
L
225 printf ("live thread clock %lx resolution %ju.%.9ju\n",
226 (unsigned long int) th_clock,
227 (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
84060bad
RM
228
229 struct timespec process_before, process_after;
230 if (clock_gettime (process_clock, &process_before) < 0)
231 {
232 printf ("clock_gettime on process clock %lx => %s\n",
fb779be7 233 (unsigned long int) process_clock, strerror (errno));
84060bad
RM
234 return 1;
235 }
236
237 struct timespec before, after;
238 if (clock_gettime (th_clock, &before) < 0)
239 {
240 printf ("clock_gettime on live thread clock %lx => %s\n",
241 (unsigned long int) th_clock, strerror (errno));
242 return 1;
243 }
5d619de4
L
244 printf ("live thread before sleep => %ju.%.9ju\n",
245 (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
84060bad
RM
246
247 struct timespec me_before, me_after;
248 if (clock_gettime (my_thread_clock, &me_before) < 0)
249 {
fb779be7
TS
250 printf ("clock_gettime on self thread clock %lx => %s\n",
251 (unsigned long int) my_thread_clock, strerror (errno));
84060bad
RM
252 return 1;
253 }
5d619de4
L
254 printf ("self thread before sleep => %ju.%.9ju\n",
255 (uintmax_t) me_before.tv_sec, (uintmax_t) me_before.tv_nsec);
84060bad
RM
256
257 struct timespec sleeptime = { .tv_nsec = 500000000 };
fb779be7
TS
258 if (nanosleep (&sleeptime, NULL) != 0)
259 {
260 perror ("nanosleep");
261 return 1;
262 }
84060bad
RM
263
264 if (clock_gettime (th_clock, &after) < 0)
265 {
266 printf ("clock_gettime on live thread clock %lx => %s\n",
267 (unsigned long int) th_clock, strerror (errno));
268 return 1;
269 }
5d619de4
L
270 printf ("live thread after sleep => %ju.%.9ju\n",
271 (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
84060bad
RM
272
273 if (clock_gettime (process_clock, &process_after) < 0)
274 {
275 printf ("clock_gettime on process clock %lx => %s\n",
fb779be7 276 (unsigned long int) process_clock, strerror (errno));
84060bad
RM
277 return 1;
278 }
279
280 if (clock_gettime (my_thread_clock, &me_after) < 0)
281 {
fb779be7
TS
282 printf ("clock_gettime on self thread clock %lx => %s\n",
283 (unsigned long int) my_thread_clock, strerror (errno));
84060bad
RM
284 return 1;
285 }
5d619de4
L
286 printf ("self thread after sleep => %ju.%.9ju\n",
287 (uintmax_t) me_after.tv_sec, (uintmax_t) me_after.tv_nsec);
84060bad
RM
288
289 unsigned long long int th_diff = tsdiff (&before, &after);
290 unsigned long long int pdiff = tsdiff (&process_before, &process_after);
291 unsigned long long int my_diff = tsdiff (&me_before, &me_after);
292
293 if (th_diff < 100000000 || th_diff > 600000000)
294 {
fb779be7 295 printf ("live thread before - after %llu outside reasonable range\n",
84060bad
RM
296 th_diff);
297 result = 1;
298 }
299
300 if (my_diff > 100000000)
301 {
302 printf ("self thread before - after %llu outside reasonable range\n",
303 my_diff);
304 result = 1;
305 }
306
307 if (pdiff < th_diff)
308 {
309 printf ("process before - after %llu outside reasonable range (%llu)\n",
310 pdiff, th_diff);
311 result = 1;
312 }
313
fb779be7 314 process_after.tv_nsec += test_nanosleep (th_clock, "live thread",
84060bad
RM
315 &after, &result);
316 process_after.tv_nsec += test_nanosleep (process_clock, "process",
317 &process_after, &result);
318 test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
319 "PROCESS_CPUTIME_ID", &process_after, &result);
320
321 pthread_cancel (th);
322
323 e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
324 if (e != EINVAL)
325 {
326 printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
327 strerror (e));
328 result = 1;
329 }
330
331 return result;
332}
333# define TIMEOUT 8
334# define TEST_FUNCTION do_test ()
335#endif
336
337#include "../test-skeleton.c"