Replace FSF snail mail address with URLs.
[glibc.git] / rt / tst-cpuclock2.c
blobd08dc6211881dad35d63f67d649b11dbbcd51d88
1 /* Test program for process and thread CPU clocks.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <unistd.h>
21 #if (_POSIX_THREADS - 0) <= 0
23 # define TEST_FUNCTION 0
25 #else
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <pthread.h>
35 static pthread_barrier_t barrier;
37 /* This function is intended to rack up both user and system time. */
38 static void *
39 chew_cpu (void *arg)
41 pthread_barrier_wait (&barrier);
43 while (1)
45 static volatile char buf[4096];
46 for (int i = 0; i < 100; ++i)
47 for (size_t j = 0; j < sizeof buf; ++j)
48 buf[j] = 0xaa;
49 int nullfd = open ("/dev/null", O_WRONLY);
50 for (int i = 0; i < 100; ++i)
51 for (size_t j = 0; j < sizeof buf; ++j)
52 buf[j] = 0xbb;
53 write (nullfd, (char *) buf, sizeof buf);
54 close (nullfd);
57 return NULL;
60 static unsigned long long int
61 tsdiff (const struct timespec *before, const struct timespec *after)
63 struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
64 .tv_nsec = after->tv_nsec - before->tv_nsec };
65 while (diff.tv_nsec < 0)
67 --diff.tv_sec;
68 diff.tv_nsec += 1000000000;
70 return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
73 static unsigned long long int
74 test_nanosleep (clockid_t clock, const char *which,
75 const struct timespec *before, int *bad)
77 const struct timespec sleeptime = { .tv_nsec = 100000000 };
78 int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
79 if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
81 printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
82 which, strerror (e));
83 return 0;
85 if (e != 0)
87 printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
88 *bad = 1;
89 return 0;
92 struct timespec after;
93 if (clock_gettime (clock, &after) < 0)
95 printf ("clock_gettime on %s CPU clock %lx => %s\n",
96 which, (unsigned long int) clock, strerror (errno));
97 *bad = 1;
98 return 0;
101 unsigned long long int diff = tsdiff (before, &after);
102 if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
104 printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
105 which, diff);
106 *bad = 1;
107 return diff;
110 struct timespec sleeptimeabs = sleeptime;
111 sleeptimeabs.tv_sec += after.tv_sec;
112 sleeptimeabs.tv_nsec += after.tv_nsec;
113 while (sleeptimeabs.tv_nsec > 1000000000)
115 ++sleeptimeabs.tv_sec;
116 sleeptimeabs.tv_nsec -= 1000000000;
118 e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
119 if (e != 0)
121 printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
122 which, strerror (e));
123 *bad = 1;
124 return diff;
127 struct timespec afterabs;
128 if (clock_gettime (clock, &afterabs) < 0)
130 printf ("clock_gettime on %s CPU clock %lx => %s\n",
131 which, (unsigned long int) clock, strerror (errno));
132 *bad = 1;
133 return diff;
136 unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
137 if (sleepdiff > sleeptime.tv_nsec)
139 printf ("\
140 absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
141 which, sleepdiff);
142 *bad = 1;
145 unsigned long long int diffabs = tsdiff (&after, &afterabs);
146 if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
148 printf ("\
149 absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
150 which, diffabs);
151 *bad = 1;
154 return diff + diffabs;
159 static int
160 do_test (void)
162 int result = 0;
163 clockid_t process_clock, th_clock, my_thread_clock;
164 int e;
165 pthread_t th;
167 e = clock_getcpuclockid (0, &process_clock);
168 if (e != 0)
170 printf ("clock_getcpuclockid on self => %s\n", strerror (e));
171 return 1;
174 e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
175 if (e != 0)
177 printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
178 return 1;
181 /* This is a kludge. This test fails if the semantics of thread and
182 process clocks are wrong. The old code using hp-timing without kernel
183 support has bogus semantics if there are context switches. We don't
184 fail to report failure when the proper functionality is not available
185 in the kernel. It so happens that Linux kernels without correct CPU
186 clock support also lack CPU timer support, so we use use that to guess
187 that we are using the bogus code and not test it. */
188 timer_t t;
189 if (timer_create (my_thread_clock, NULL, &t) != 0)
191 printf ("timer_create: %m\n");
192 puts ("No support for CPU clocks with good semantics, skipping test");
193 return 0;
195 timer_delete (t);
198 pthread_barrier_init (&barrier, NULL, 2);
200 e = pthread_create (&th, NULL, chew_cpu, NULL);
201 if (e != 0)
203 printf ("pthread_create: %s\n", strerror (e));
204 return 1;
207 e = pthread_getcpuclockid (th, &th_clock);
208 if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
210 puts ("pthread_getcpuclockid does not support other threads");
211 return 1;
214 pthread_barrier_wait (&barrier);
216 struct timespec res;
217 if (clock_getres (th_clock, &res) < 0)
219 printf ("clock_getres on thread clock %lx => %s\n",
220 (unsigned long int) th_clock, strerror (errno));
221 result = 1;
222 return 1;
224 printf ("live thread clock %lx resolution %lu.%.9lu\n",
225 (unsigned long int) th_clock, res.tv_sec, res.tv_nsec);
227 struct timespec process_before, process_after;
228 if (clock_gettime (process_clock, &process_before) < 0)
230 printf ("clock_gettime on process clock %lx => %s\n",
231 (unsigned long int) th_clock, strerror (errno));
232 return 1;
235 struct timespec before, after;
236 if (clock_gettime (th_clock, &before) < 0)
238 printf ("clock_gettime on live thread clock %lx => %s\n",
239 (unsigned long int) th_clock, strerror (errno));
240 return 1;
242 printf ("live thread before sleep => %lu.%.9lu\n",
243 before.tv_sec, before.tv_nsec);
245 struct timespec me_before, me_after;
246 if (clock_gettime (my_thread_clock, &me_before) < 0)
248 printf ("clock_gettime on live thread clock %lx => %s\n",
249 (unsigned long int) th_clock, strerror (errno));
250 return 1;
252 printf ("self thread before sleep => %lu.%.9lu\n",
253 me_before.tv_sec, me_before.tv_nsec);
255 struct timespec sleeptime = { .tv_nsec = 500000000 };
256 nanosleep (&sleeptime, NULL);
258 if (clock_gettime (th_clock, &after) < 0)
260 printf ("clock_gettime on live thread clock %lx => %s\n",
261 (unsigned long int) th_clock, strerror (errno));
262 return 1;
264 printf ("live thread after sleep => %lu.%.9lu\n",
265 after.tv_sec, after.tv_nsec);
267 if (clock_gettime (process_clock, &process_after) < 0)
269 printf ("clock_gettime on process clock %lx => %s\n",
270 (unsigned long int) th_clock, strerror (errno));
271 return 1;
274 if (clock_gettime (my_thread_clock, &me_after) < 0)
276 printf ("clock_gettime on live thread clock %lx => %s\n",
277 (unsigned long int) th_clock, strerror (errno));
278 return 1;
280 printf ("self thread after sleep => %lu.%.9lu\n",
281 me_after.tv_sec, me_after.tv_nsec);
283 unsigned long long int th_diff = tsdiff (&before, &after);
284 unsigned long long int pdiff = tsdiff (&process_before, &process_after);
285 unsigned long long int my_diff = tsdiff (&me_before, &me_after);
287 if (th_diff < 100000000 || th_diff > 600000000)
289 printf ("thread before - after %llu outside reasonable range\n",
290 th_diff);
291 result = 1;
294 if (my_diff > 100000000)
296 printf ("self thread before - after %llu outside reasonable range\n",
297 my_diff);
298 result = 1;
301 if (pdiff < th_diff)
303 printf ("process before - after %llu outside reasonable range (%llu)\n",
304 pdiff, th_diff);
305 result = 1;
308 process_after.tv_nsec += test_nanosleep (th_clock, "thread",
309 &after, &result);
310 process_after.tv_nsec += test_nanosleep (process_clock, "process",
311 &process_after, &result);
312 test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
313 "PROCESS_CPUTIME_ID", &process_after, &result);
315 pthread_cancel (th);
317 e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
318 if (e != EINVAL)
320 printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
321 strerror (e));
322 result = 1;
325 return result;
327 # define TIMEOUT 8
328 # define TEST_FUNCTION do_test ()
329 #endif
331 #include "../test-skeleton.c"