Replace %ld/%lu with %jd/%ju and cast to intmax_t/uintmax_t
[platform/upstream/glibc.git] / rt / tst-cpuclock2.c
1 /* Test program for process and thread CPU clocks.
2    Copyright (C) 2005-2014 Free Software Foundation, Inc.
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
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <unistd.h>
20 #include <stdint.h>
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
36 static pthread_barrier_t barrier;
37
38 /* This function is intended to rack up both user and system time.  */
39 static void *
40 chew_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
61 static unsigned long long int
62 tsdiff (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
74 static unsigned long long int
75 test_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;
114   while (sleeptimeabs.tv_nsec >= 1000000000)
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 ("\
141 absolute 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 ("\
150 absolute 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
160 static int
161 do_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     {
220       printf ("clock_getres on live thread clock %lx => %s\n",
221               (unsigned long int) th_clock, strerror (errno));
222       result = 1;
223       return 1;
224     }
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);
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",
233               (unsigned long int) process_clock, strerror (errno));
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     }
244   printf ("live thread before sleep => %ju.%.9ju\n",
245           (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
246
247   struct timespec me_before, me_after;
248   if (clock_gettime (my_thread_clock, &me_before) < 0)
249     {
250       printf ("clock_gettime on self thread clock %lx => %s\n",
251               (unsigned long int) my_thread_clock, strerror (errno));
252       return 1;
253     }
254   printf ("self thread before sleep => %ju.%.9ju\n",
255           (uintmax_t) me_before.tv_sec, (uintmax_t) me_before.tv_nsec);
256
257   struct timespec sleeptime = { .tv_nsec = 500000000 };
258   if (nanosleep (&sleeptime, NULL) != 0)
259     {
260       perror ("nanosleep");
261       return 1;
262     }
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     }
270   printf ("live thread after sleep => %ju.%.9ju\n",
271           (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
272
273   if (clock_gettime (process_clock, &process_after) < 0)
274     {
275       printf ("clock_gettime on process clock %lx => %s\n",
276               (unsigned long int) process_clock, strerror (errno));
277       return 1;
278     }
279
280   if (clock_gettime (my_thread_clock, &me_after) < 0)
281     {
282       printf ("clock_gettime on self thread clock %lx => %s\n",
283               (unsigned long int) my_thread_clock, strerror (errno));
284       return 1;
285     }
286   printf ("self thread after sleep => %ju.%.9ju\n",
287           (uintmax_t) me_after.tv_sec, (uintmax_t) me_after.tv_nsec);
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     {
295       printf ("live thread before - after %llu outside reasonable range\n",
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
314   process_after.tv_nsec += test_nanosleep (th_clock, "live thread",
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"