timevar: import from Bison.
[gnulib.git] / lib / timevar.c
blob0578816a3b4f0805971f8d2bd0bc55d901ada2d1
1 /* Timing variables for measuring compiler performance.
3 Copyright (C) 2000, 2002, 2004, 2006, 2009-2015, 2018 Free Software
4 Foundation, Inc.
6 Contributed by Alex Samuel <samuel@codesourcery.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
27 #include "gettext.h"
28 #define _(msgid) gettext (msgid)
29 #include "xalloc.h"
31 #if HAVE_SYS_TIME_H
32 # include <sys/time.h>
33 #endif
35 #ifdef HAVE_SYS_TIMES_H
36 # include <sys/times.h>
37 #endif
38 #ifdef HAVE_SYS_RESOURCE_H
39 # include <sys/resource.h>
40 #endif
42 #ifndef HAVE_CLOCK_T
43 typedef int clock_t;
44 #endif
46 #ifndef HAVE_STRUCT_TMS
47 struct tms
49 clock_t tms_utime;
50 clock_t tms_stime;
51 clock_t tms_cutime;
52 clock_t tms_cstime;
54 #endif
56 /* Calculation of scale factor to convert ticks to microseconds.
57 We mustn't use CLOCKS_PER_SEC except with clock(). */
58 #if HAVE_SYSCONF && defined _SC_CLK_TCK
59 # define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
60 #elif defined CLK_TCK
61 # define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
62 #elif defined HZ
63 # define TICKS_PER_SECOND HZ /* traditional UNIX */
64 #else
65 # define TICKS_PER_SECOND 100 /* often the correct value */
66 #endif
68 /* Prefer times to getrusage to clock (each gives successively less
69 information). */
70 #if defined HAVE_TIMES
71 # define USE_TIMES
72 # define HAVE_USER_TIME
73 # define HAVE_SYS_TIME
74 # define HAVE_WALL_TIME
75 #elif defined HAVE_GETRUSAGE
76 # define USE_GETRUSAGE
77 # define HAVE_USER_TIME
78 # define HAVE_SYS_TIME
79 #elif defined HAVE_CLOCK
80 # define USE_CLOCK
81 # define HAVE_USER_TIME
82 #endif
84 #if defined USE_TIMES && !defined HAVE_DECL_TIMES
85 clock_t times (struct tms *);
86 #elif defined USE_GETRUSAGE && !defined HAVE_DECL_GETRUSAGE
87 int getrusage (int, struct rusage *);
88 #elif defined USE_CLOCK && !defined HAVE_DECL_CLOCK
89 clock_t clock (void);
90 #endif
92 /* libc is very likely to have snuck a call to sysconf() into one of
93 the underlying constants, and that can be very slow, so we have to
94 precompute them. Whose wonderful idea was it to make all those
95 _constants_ variable at run time, anyway? */
96 #ifdef USE_TIMES
97 static float ticks_to_msec;
98 # define TICKS_TO_MSEC (1.0 / TICKS_PER_SECOND)
99 #elif defined USE_CLOCK
100 static float clocks_to_msec;
101 # define CLOCKS_TO_MSEC (1.0 / CLOCKS_PER_SEC)
102 #endif
104 #include "timevar.h"
106 /* See timevar.h for an explanation of timing variables. */
108 int timevar_enabled = 0;
110 /* A timing variable. */
112 struct timevar_def
114 /* Elapsed time for this variable. */
115 struct timevar_time_def elapsed;
117 /* If this variable is timed independently of the timing stack,
118 using timevar_start, this contains the start time. */
119 struct timevar_time_def start_time;
121 /* The name of this timing variable. */
122 const char *name;
124 /* Non-zero if this timing variable is running as a standalone
125 timer. */
126 unsigned standalone : 1;
128 /* Non-zero if this timing variable was ever started or pushed onto
129 the timing stack. */
130 unsigned used : 1;
133 /* An element on the timing stack. Elapsed time is attributed to the
134 topmost timing variable on the stack. */
136 struct timevar_stack_def
138 /* The timing variable at this stack level. */
139 struct timevar_def *timevar;
141 /* The next lower timing variable context in the stack. */
142 struct timevar_stack_def *next;
145 /* Declared timing variables. Constructed from the contents of
146 timevar.def. */
147 static struct timevar_def timevars[TIMEVAR_LAST];
149 /* The top of the timing stack. */
150 static struct timevar_stack_def *stack;
152 /* A list of unused (i.e. allocated and subsequently popped)
153 timevar_stack_def instances. */
154 static struct timevar_stack_def *unused_stack_instances;
156 /* The time at which the topmost element on the timing stack was
157 pushed. Time elapsed since then is attributed to the topmost
158 element. */
159 static struct timevar_time_def start_time;
161 /* Fill the current times into TIME. The definition of this function
162 also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
163 HAVE_WALL_TIME macros. */
165 static void
166 set_to_current_time (struct timevar_time_def *now)
168 now->user = 0;
169 now->sys = 0;
170 now->wall = 0;
172 if (!timevar_enabled)
173 return;
176 #ifdef USE_TIMES
177 struct tms tms;
178 now->wall = times (&tms) * ticks_to_msec;
179 now->user = (tms.tms_utime + tms.tms_cutime) * ticks_to_msec;
180 now->sys = (tms.tms_stime + tms.tms_cstime) * ticks_to_msec;
181 #elif defined USE_GETRUSAGE
182 struct rusage rusage;
183 getrusage (RUSAGE_CHILDREN, &rusage);
184 now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6;
185 now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6;
186 #elif defined USE_CLOCK
187 now->user = clock () * clocks_to_msec;
188 #endif
192 /* Return the current time. */
194 static struct timevar_time_def
195 get_current_time (void)
197 struct timevar_time_def now;
198 set_to_current_time (&now);
199 return now;
202 /* Add the difference between STOP and START to TIMER. */
204 static void
205 timevar_accumulate (struct timevar_time_def *timer,
206 const struct timevar_time_def *start,
207 const struct timevar_time_def *stop)
209 timer->user += stop->user - start->user;
210 timer->sys += stop->sys - start->sys;
211 timer->wall += stop->wall - start->wall;
214 void
215 timevar_init ()
217 if (!timevar_enabled)
218 return;
220 /* Zero all elapsed times. */
221 memset ((void *) timevars, 0, sizeof (timevars));
223 /* Initialize the names of timing variables. */
224 #define DEFTIMEVAR(identifier__, name__) \
225 timevars[identifier__].name = name__;
226 #include "timevar.def"
227 #undef DEFTIMEVAR
229 #if defined USE_TIMES
230 ticks_to_msec = TICKS_TO_MSEC;
231 #elif defined USE_CLOCK
232 clocks_to_msec = CLOCKS_TO_MSEC;
233 #endif
236 void
237 timevar_push (timevar_id_t timevar)
239 if (!timevar_enabled)
240 return;
242 struct timevar_def *tv = &timevars[timevar];
244 /* Mark this timing variable as used. */
245 tv->used = 1;
247 /* Can't push a standalone timer. */
248 if (tv->standalone)
249 abort ();
251 /* What time is it? */
252 struct timevar_time_def const now = get_current_time ();
254 /* If the stack isn't empty, attribute the current elapsed time to
255 the old topmost element. */
256 if (stack)
257 timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
259 /* Reset the start time; from now on, time is attributed to
260 TIMEVAR. */
261 start_time = now;
263 /* See if we have a previously-allocated stack instance. If so,
264 take it off the list. If not, malloc a new one. */
265 struct timevar_stack_def *context = NULL;
266 if (unused_stack_instances != NULL)
268 context = unused_stack_instances;
269 unused_stack_instances = unused_stack_instances->next;
271 else
272 context = (struct timevar_stack_def *)
273 xmalloc (sizeof (struct timevar_stack_def));
275 /* Fill it in and put it on the stack. */
276 context->timevar = tv;
277 context->next = stack;
278 stack = context;
281 void
282 timevar_pop (timevar_id_t timevar)
284 if (!timevar_enabled)
285 return;
287 if (&timevars[timevar] != stack->timevar)
288 abort ();
290 /* What time is it? */
291 struct timevar_time_def const now = get_current_time ();
293 /* Attribute the elapsed time to the element we're popping. */
294 struct timevar_stack_def *popped = stack;
295 timevar_accumulate (&popped->timevar->elapsed, &start_time, &now);
297 /* Reset the start time; from now on, time is attributed to the
298 element just exposed on the stack. */
299 start_time = now;
301 /* Take the item off the stack. */
302 stack = stack->next;
304 /* Don't delete the stack element; instead, add it to the list of
305 unused elements for later use. */
306 popped->next = unused_stack_instances;
307 unused_stack_instances = popped;
310 void
311 timevar_start (timevar_id_t timevar)
313 if (!timevar_enabled)
314 return;
316 struct timevar_def *tv = &timevars[timevar];
318 /* Mark this timing variable as used. */
319 tv->used = 1;
321 /* Don't allow the same timing variable to be started more than
322 once. */
323 if (tv->standalone)
324 abort ();
325 tv->standalone = 1;
327 set_to_current_time (&tv->start_time);
330 void
331 timevar_stop (timevar_id_t timevar)
333 if (!timevar_enabled)
334 return;
336 struct timevar_def *tv = &timevars[timevar];
338 /* TIMEVAR must have been started via timevar_start. */
339 if (!tv->standalone)
340 abort ();
342 struct timevar_time_def const now = get_current_time ();
343 timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
346 void
347 timevar_get (timevar_id_t timevar,
348 struct timevar_time_def *elapsed)
350 struct timevar_def *tv = &timevars[timevar];
351 *elapsed = tv->elapsed;
353 /* Is TIMEVAR currently running as a standalone timer? */
354 if (tv->standalone)
356 struct timevar_time_def const now = get_current_time ();
357 timevar_accumulate (elapsed, &tv->start_time, &now);
359 /* Or is TIMEVAR at the top of the timer stack? */
360 else if (stack->timevar == tv)
362 struct timevar_time_def const now = get_current_time ();
363 timevar_accumulate (elapsed, &start_time, &now);
367 void
368 timevar_print (FILE *fp)
370 /* Only print stuff if we have some sort of time information. */
371 #if defined HAVE_USER_TIME || defined HAVE_SYS_TIME || defined HAVE_WALL_TIME
372 if (!timevar_enabled)
373 return;
375 /* Update timing information in case we're calling this from GDB. */
377 if (fp == 0)
378 fp = stderr;
380 /* What time is it? */
381 struct timevar_time_def const now = get_current_time ();
383 /* If the stack isn't empty, attribute the current elapsed time to
384 the old topmost element. */
385 if (stack)
386 timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
388 /* Reset the start time; from now on, time is attributed to
389 TIMEVAR. */
390 start_time = now;
392 struct timevar_time_def const* total = &timevars[tv_total].elapsed;
394 fputs (_("\nExecution times (seconds)\n"), fp);
395 for (unsigned /* timevar_id_t */ id = 0; id < (unsigned) TIMEVAR_LAST; ++id)
397 struct timevar_def *tv = &timevars[(timevar_id_t) id];
398 const float tiny = 5e-3;
400 /* Don't print the total execution time here; that goes at the
401 end. */
402 if ((timevar_id_t) id == tv_total)
403 continue;
405 /* Don't print timing variables that were never used. */
406 if (!tv->used)
407 continue;
409 /* Don't print timing variables if we're going to get a row of
410 zeroes. */
411 if (tv->elapsed.user < tiny
412 && tv->elapsed.sys < tiny
413 && tv->elapsed.wall < tiny)
414 continue;
416 /* The timing variable name. */
417 fprintf (fp, " %-22s:", tv->name);
419 # ifdef HAVE_USER_TIME
420 /* Print user-mode time for this process. */
421 fprintf (fp, "%7.2f (%2.0f%%) usr",
422 tv->elapsed.user,
423 (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
424 # endif
426 # ifdef HAVE_SYS_TIME
427 /* Print system-mode time for this process. */
428 fprintf (fp, "%7.2f (%2.0f%%) sys",
429 tv->elapsed.sys,
430 (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
431 # endif
433 # ifdef HAVE_WALL_TIME
434 /* Print wall clock time elapsed. */
435 fprintf (fp, "%7.2f (%2.0f%%) wall",
436 tv->elapsed.wall,
437 (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
438 # endif
440 putc ('\n', fp);
443 /* Print total time. */
444 fprintf (fp, " %-22s:", timevars[tv_total].name);
445 #ifdef HAVE_USER_TIME
446 fprintf (fp, "%7.2f ", total->user);
447 #endif
448 #ifdef HAVE_SYS_TIME
449 fprintf (fp, "%7.2f ", total->sys);
450 #endif
451 #ifdef HAVE_WALL_TIME
452 fprintf (fp, "%7.2f\n", total->wall);
453 #endif
455 #endif /* defined HAVE_USER_TIME || defined HAVE_SYS_TIME || defined HAVE_WALL_TIME */