Updates and formatting changes.
[glibc/history.git] / rt / tst-cpuclock2.c
blobd1621f3d010fa37f733268fbf711c8f3c031efa2
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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <unistd.h>
22 #if (_POSIX_THREADS - 0) <= 0
24 # define TEST_FUNCTION 0
26 #else
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>
36 static pthread_barrier_t barrier;
38 /* This function is intended to rack up both user and system time. */
39 static void *
40 chew_cpu (void *arg)
42 pthread_barrier_wait (&barrier);
44 while (1)
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);
58 return NULL;
61 static unsigned long long int
62 tsdiff (const struct timespec *before, const struct timespec *after)
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)
68 --diff.tv_sec;
69 diff.tv_nsec += 1000000000;
71 return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
74 static unsigned long long int
75 test_nanosleep (clockid_t clock, const char *which,
76 const struct timespec *before, int *bad)
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)
82 printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
83 which, strerror (e));
84 return 0;
86 if (e != 0)
88 printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
89 *bad = 1;
90 return 0;
93 struct timespec after;
94 if (clock_gettime (clock, &after) < 0)
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;
102 unsigned long long int diff = tsdiff (before, &after);
103 if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
105 printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
106 which, diff);
107 *bad = 1;
108 return diff;
111 struct timespec sleeptimeabs = sleeptime;
112 sleeptimeabs.tv_sec += after.tv_sec;
113 sleeptimeabs.tv_nsec += after.tv_nsec;
114 while (sleeptimeabs.tv_nsec > 1000000000)
116 ++sleeptimeabs.tv_sec;
117 sleeptimeabs.tv_nsec -= 1000000000;
119 e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
120 if (e != 0)
122 printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
123 which, strerror (e));
124 *bad = 1;
125 return diff;
128 struct timespec afterabs;
129 if (clock_gettime (clock, &afterabs) < 0)
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;
137 unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
138 if (sleepdiff > sleeptime.tv_nsec)
140 printf ("\
141 absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
142 which, sleepdiff);
143 *bad = 1;
146 unsigned long long int diffabs = tsdiff (&after, &afterabs);
147 if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
149 printf ("\
150 absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
151 which, diffabs);
152 *bad = 1;
155 return diff + diffabs;
160 static int
161 do_test (void)
163 int result = 0;
164 clockid_t process_clock, th_clock, my_thread_clock;
165 int e;
166 pthread_t th;
168 e = clock_getcpuclockid (0, &process_clock);
169 if (e != 0)
171 printf ("clock_getcpuclockid on self => %s\n", strerror (e));
172 return 1;
175 e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
176 if (e != 0)
178 printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
179 return 1;
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)
192 printf ("timer_create: %m\n");
193 puts ("No support for CPU clocks with good semantics, skipping test");
194 return 0;
196 timer_delete (t);
199 pthread_barrier_init (&barrier, NULL, 2);
201 e = pthread_create (&th, NULL, chew_cpu, NULL);
202 if (e != 0)
204 printf ("pthread_create: %s\n", strerror (e));
205 return 1;
208 e = pthread_getcpuclockid (th, &th_clock);
209 if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
211 puts ("pthread_getcpuclockid does not support other threads");
212 return 1;
215 pthread_barrier_wait (&barrier);
217 struct timespec res;
218 if (clock_getres (th_clock, &res) < 0)
220 printf ("clock_getres on thread clock %lx => %s\n",
221 (unsigned long int) th_clock, strerror (errno));
222 result = 1;
223 return 1;
225 printf ("live thread clock %lx resolution %lu.%.9lu\n",
226 (unsigned long int) th_clock, res.tv_sec, res.tv_nsec);
228 struct timespec process_before, process_after;
229 if (clock_gettime (process_clock, &process_before) < 0)
231 printf ("clock_gettime on process clock %lx => %s\n",
232 (unsigned long int) th_clock, strerror (errno));
233 return 1;
236 struct timespec before, after;
237 if (clock_gettime (th_clock, &before) < 0)
239 printf ("clock_gettime on live thread clock %lx => %s\n",
240 (unsigned long int) th_clock, strerror (errno));
241 return 1;
243 printf ("live thread before sleep => %lu.%.9lu\n",
244 before.tv_sec, before.tv_nsec);
246 struct timespec me_before, me_after;
247 if (clock_gettime (my_thread_clock, &me_before) < 0)
249 printf ("clock_gettime on live thread clock %lx => %s\n",
250 (unsigned long int) th_clock, strerror (errno));
251 return 1;
253 printf ("self thread before sleep => %lu.%.9lu\n",
254 me_before.tv_sec, me_before.tv_nsec);
256 struct timespec sleeptime = { .tv_nsec = 500000000 };
257 nanosleep (&sleeptime, NULL);
259 if (clock_gettime (th_clock, &after) < 0)
261 printf ("clock_gettime on live thread clock %lx => %s\n",
262 (unsigned long int) th_clock, strerror (errno));
263 return 1;
265 printf ("live thread after sleep => %lu.%.9lu\n",
266 after.tv_sec, after.tv_nsec);
268 if (clock_gettime (process_clock, &process_after) < 0)
270 printf ("clock_gettime on process clock %lx => %s\n",
271 (unsigned long int) th_clock, strerror (errno));
272 return 1;
275 if (clock_gettime (my_thread_clock, &me_after) < 0)
277 printf ("clock_gettime on live thread clock %lx => %s\n",
278 (unsigned long int) th_clock, strerror (errno));
279 return 1;
281 printf ("self thread after sleep => %lu.%.9lu\n",
282 me_after.tv_sec, me_after.tv_nsec);
284 unsigned long long int th_diff = tsdiff (&before, &after);
285 unsigned long long int pdiff = tsdiff (&process_before, &process_after);
286 unsigned long long int my_diff = tsdiff (&me_before, &me_after);
288 if (th_diff < 100000000 || th_diff > 600000000)
290 printf ("thread before - after %llu outside reasonable range\n",
291 th_diff);
292 result = 1;
295 if (my_diff > 100000000)
297 printf ("self thread before - after %llu outside reasonable range\n",
298 my_diff);
299 result = 1;
302 if (pdiff < th_diff)
304 printf ("process before - after %llu outside reasonable range (%llu)\n",
305 pdiff, th_diff);
306 result = 1;
309 process_after.tv_nsec += test_nanosleep (th_clock, "thread",
310 &after, &result);
311 process_after.tv_nsec += test_nanosleep (process_clock, "process",
312 &process_after, &result);
313 test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
314 "PROCESS_CPUTIME_ID", &process_after, &result);
316 pthread_cancel (th);
318 e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
319 if (e != EINVAL)
321 printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
322 strerror (e));
323 result = 1;
326 return result;
328 # define TIMEOUT 8
329 # define TEST_FUNCTION do_test ()
330 #endif
332 #include "../test-skeleton.c"