Update ChangeLog.old/ChangeLog.23.
[glibc.git] / rt / tst-cpuclock2.c
blobeebc3609d0aa88dadf24137ad4c8461deef38617
1 /* Test program for process and thread CPU clocks.
2 Copyright (C) 2005-2021 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 <https://www.gnu.org/licenses/>. */
19 #include <unistd.h>
20 #include <stdint.h>
22 #if (_POSIX_THREADS - 0) <= 0
24 static int
25 do_test ()
27 return 0;
30 #else
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <pthread.h>
40 static pthread_barrier_t barrier;
42 /* This function is intended to rack up both user and system time. */
43 static void *
44 chew_cpu (void *arg)
46 pthread_barrier_wait (&barrier);
48 while (1)
50 static volatile char buf[4096];
51 for (int i = 0; i < 100; ++i)
52 for (size_t j = 0; j < sizeof buf; ++j)
53 buf[j] = 0xaa;
54 int nullfd = open ("/dev/null", O_WRONLY);
55 for (int i = 0; i < 100; ++i)
56 for (size_t j = 0; j < sizeof buf; ++j)
57 buf[j] = 0xbb;
58 write (nullfd, (char *) buf, sizeof buf);
59 close (nullfd);
62 return NULL;
65 static unsigned long long int
66 tsdiff (const struct timespec *before, const struct timespec *after)
68 struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
69 .tv_nsec = after->tv_nsec - before->tv_nsec };
70 while (diff.tv_nsec < 0)
72 --diff.tv_sec;
73 diff.tv_nsec += 1000000000;
75 return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
78 static unsigned long long int
79 test_nanosleep (clockid_t clock, const char *which,
80 const struct timespec *before, int *bad)
82 const struct timespec sleeptime = { .tv_nsec = 100000000 };
83 int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
84 if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
86 printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
87 which, strerror (e));
88 return 0;
90 if (e != 0)
92 printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
93 *bad = 1;
94 return 0;
97 struct timespec after;
98 if (clock_gettime (clock, &after) < 0)
100 printf ("clock_gettime on %s CPU clock %lx => %s\n",
101 which, (unsigned long int) clock, strerror (errno));
102 *bad = 1;
103 return 0;
106 unsigned long long int diff = tsdiff (before, &after);
107 if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
109 printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
110 which, diff);
111 *bad = 1;
112 return diff;
115 struct timespec sleeptimeabs = sleeptime;
116 sleeptimeabs.tv_sec += after.tv_sec;
117 sleeptimeabs.tv_nsec += after.tv_nsec;
118 while (sleeptimeabs.tv_nsec >= 1000000000)
120 ++sleeptimeabs.tv_sec;
121 sleeptimeabs.tv_nsec -= 1000000000;
123 e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
124 if (e != 0)
126 printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
127 which, strerror (e));
128 *bad = 1;
129 return diff;
132 struct timespec afterabs;
133 if (clock_gettime (clock, &afterabs) < 0)
135 printf ("clock_gettime on %s CPU clock %lx => %s\n",
136 which, (unsigned long int) clock, strerror (errno));
137 *bad = 1;
138 return diff;
141 unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
142 if (sleepdiff > sleeptime.tv_nsec)
144 printf ("\
145 absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
146 which, sleepdiff);
147 *bad = 1;
150 unsigned long long int diffabs = tsdiff (&after, &afterabs);
151 if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
153 printf ("\
154 absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
155 which, diffabs);
156 *bad = 1;
159 return diff + diffabs;
164 static int
165 do_test (void)
167 int result = 0;
168 clockid_t process_clock, th_clock, my_thread_clock;
169 int e;
170 pthread_t th;
172 e = clock_getcpuclockid (0, &process_clock);
173 if (e != 0)
175 printf ("clock_getcpuclockid on self => %s\n", strerror (e));
176 return 1;
179 e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
180 if (e != 0)
182 printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
183 return 1;
186 /* This is a kludge. This test fails if the semantics of thread and
187 process clocks are wrong. The old code using hp-timing without kernel
188 support has bogus semantics if there are context switches. We don't
189 fail to report failure when the proper functionality is not available
190 in the kernel. It so happens that Linux kernels without correct CPU
191 clock support also lack CPU timer support, so we use use that to guess
192 that we are using the bogus code and not test it. */
193 timer_t t;
194 if (timer_create (my_thread_clock, NULL, &t) != 0)
196 printf ("timer_create: %m\n");
197 puts ("No support for CPU clocks with good semantics, skipping test");
198 return 0;
200 timer_delete (t);
203 pthread_barrier_init (&barrier, NULL, 2);
205 e = pthread_create (&th, NULL, chew_cpu, NULL);
206 if (e != 0)
208 printf ("pthread_create: %s\n", strerror (e));
209 return 1;
212 e = pthread_getcpuclockid (th, &th_clock);
213 if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
215 puts ("pthread_getcpuclockid does not support other threads");
216 return 1;
219 pthread_barrier_wait (&barrier);
221 struct timespec res;
222 if (clock_getres (th_clock, &res) < 0)
224 printf ("clock_getres on live thread clock %lx => %s\n",
225 (unsigned long int) th_clock, strerror (errno));
226 result = 1;
227 return 1;
229 printf ("live thread clock %lx resolution %ju.%.9ju\n",
230 (unsigned long int) th_clock,
231 (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
233 struct timespec process_before, process_after;
234 if (clock_gettime (process_clock, &process_before) < 0)
236 printf ("clock_gettime on process clock %lx => %s\n",
237 (unsigned long int) process_clock, strerror (errno));
238 return 1;
241 struct timespec before, after;
242 if (clock_gettime (th_clock, &before) < 0)
244 printf ("clock_gettime on live thread clock %lx => %s\n",
245 (unsigned long int) th_clock, strerror (errno));
246 return 1;
248 printf ("live thread before sleep => %ju.%.9ju\n",
249 (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
251 struct timespec me_before, me_after;
252 if (clock_gettime (my_thread_clock, &me_before) < 0)
254 printf ("clock_gettime on self thread clock %lx => %s\n",
255 (unsigned long int) my_thread_clock, strerror (errno));
256 return 1;
258 printf ("self thread before sleep => %ju.%.9ju\n",
259 (uintmax_t) me_before.tv_sec, (uintmax_t) me_before.tv_nsec);
261 struct timespec sleeptime = { .tv_nsec = 500000000 };
262 if (nanosleep (&sleeptime, NULL) != 0)
264 perror ("nanosleep");
265 return 1;
268 if (clock_gettime (th_clock, &after) < 0)
270 printf ("clock_gettime on live thread clock %lx => %s\n",
271 (unsigned long int) th_clock, strerror (errno));
272 return 1;
274 printf ("live thread after sleep => %ju.%.9ju\n",
275 (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
277 if (clock_gettime (process_clock, &process_after) < 0)
279 printf ("clock_gettime on process clock %lx => %s\n",
280 (unsigned long int) process_clock, strerror (errno));
281 return 1;
284 if (clock_gettime (my_thread_clock, &me_after) < 0)
286 printf ("clock_gettime on self thread clock %lx => %s\n",
287 (unsigned long int) my_thread_clock, strerror (errno));
288 return 1;
290 printf ("self thread after sleep => %ju.%.9ju\n",
291 (uintmax_t) me_after.tv_sec, (uintmax_t) me_after.tv_nsec);
293 unsigned long long int th_diff = tsdiff (&before, &after);
294 unsigned long long int pdiff = tsdiff (&process_before, &process_after);
295 unsigned long long int my_diff = tsdiff (&me_before, &me_after);
297 if (th_diff < 100000000 || th_diff > 600000000)
299 printf ("live thread before - after %llu outside reasonable range\n",
300 th_diff);
301 result = 1;
304 if (my_diff > 100000000)
306 printf ("self thread before - after %llu outside reasonable range\n",
307 my_diff);
308 result = 1;
311 if (pdiff < th_diff)
313 printf ("process before - after %llu outside reasonable range (%llu)\n",
314 pdiff, th_diff);
315 result = 1;
318 process_after.tv_nsec += test_nanosleep (th_clock, "live thread",
319 &after, &result);
320 process_after.tv_nsec += test_nanosleep (process_clock, "process",
321 &process_after, &result);
322 test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
323 "PROCESS_CPUTIME_ID", &process_after, &result);
325 pthread_cancel (th);
327 e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
328 if (e != EINVAL)
330 printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
331 strerror (e));
332 result = 1;
335 return result;
337 #endif
339 #include <support/test-driver.c>