]> git.saurik.com Git - bison.git/blame - lib/timevar.c
Work around portability problem on Solaris 10: flex-generated
[bison.git] / lib / timevar.c
CommitLineData
1509d42f 1/* Timing variables for measuring compiler performance.
2cec9080 2 Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation, Inc.
1509d42f
AD
3 Contributed by Alex Samuel <samuel@codesourcery.com>
4
fdabfd76 5This file is part of Bison, the GNU Compiler Compiler.
1509d42f 6
fdabfd76 7Bison is free software; you can redistribute it and/or modify it under
1509d42f
AD
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
fdabfd76 12Bison is distributed in the hope that it will be useful, but WITHOUT ANY
1509d42f
AD
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
fdabfd76 18along with Bison; see the file COPYING. If not, write to the Free
0fb669f9
PE
19Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301, USA. */
1509d42f 21
2cec9080
PE
22#include "config.h"
23
fdabfd76
PE
24#if IN_GCC
25
1509d42f
AD
26#include "system.h"
27#include "intl.h"
28#include "rtl.h"
29
fdabfd76
PE
30#else
31
32/* This source file is taken from the GCC source code, with slight
33 modifications that are under control of the IN_GCC preprocessor
34 variable. The !IN_GCC part of this file is specific to Bison. */
04098407 35
fdabfd76
PE
36# include "../src/system.h"
37# if HAVE_SYS_TIME_H
38# include <sys/time.h>
39# endif
e22ad7fa 40int timevar_report = 0;
fdabfd76
PE
41
42#endif
43
44
1509d42f
AD
45#ifdef HAVE_SYS_TIMES_H
46# include <sys/times.h>
47#endif
48#ifdef HAVE_SYS_RESOURCE_H
49#include <sys/resource.h>
50#endif
51
52#ifndef HAVE_CLOCK_T
53typedef int clock_t;
54#endif
55
56#ifndef HAVE_STRUCT_TMS
57struct tms
58{
59 clock_t tms_utime;
60 clock_t tms_stime;
61 clock_t tms_cutime;
62 clock_t tms_cstime;
63};
64#endif
65
66#if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
126e3751 67extern int getrusage (int, struct rusage *);
1509d42f
AD
68#endif
69#if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
126e3751 70extern clock_t times (struct tms *);
1509d42f
AD
71#endif
72#if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
126e3751 73extern clock_t clock (void);
1509d42f
AD
74#endif
75
76#ifndef RUSAGE_SELF
77# define RUSAGE_SELF 0
78#endif
79
80/* Calculation of scale factor to convert ticks to microseconds.
81 We mustn't use CLOCKS_PER_SEC except with clock(). */
82#if HAVE_SYSCONF && defined _SC_CLK_TCK
83# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
84#else
85# ifdef CLK_TCK
86# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
87# else
88# ifdef HZ
89# define TICKS_PER_SECOND HZ /* traditional UNIX */
90# else
91# define TICKS_PER_SECOND 100 /* often the correct value */
92# endif
93# endif
94#endif
95
96/* Prefer times to getrusage to clock (each gives successively less
97 information). */
98#ifdef HAVE_TIMES
99# define USE_TIMES
100# define HAVE_USER_TIME
101# define HAVE_SYS_TIME
102# define HAVE_WALL_TIME
103#else
104#ifdef HAVE_GETRUSAGE
105# define USE_GETRUSAGE
106# define HAVE_USER_TIME
107# define HAVE_SYS_TIME
108#else
109#ifdef HAVE_CLOCK
110# define USE_CLOCK
111# define HAVE_USER_TIME
112#endif
113#endif
114#endif
115
116/* libc is very likely to have snuck a call to sysconf() into one of
117 the underlying constants, and that can be very slow, so we have to
118 precompute them. Whose wonderful idea was it to make all those
119 _constants_ variable at run time, anyway? */
120#ifdef USE_TIMES
121static float ticks_to_msec;
9e2c5ef1 122#define TICKS_TO_MSEC (1.0 / TICKS_PER_SECOND)
1509d42f
AD
123#endif
124
125#ifdef USE_CLOCK
126static float clocks_to_msec;
9e2c5ef1 127#define CLOCKS_TO_MSEC (1.0 / CLOCKS_PER_SEC)
1509d42f
AD
128#endif
129
fdabfd76 130#if IN_GCC
1509d42f 131#include "flags.h"
fdabfd76 132#endif
1509d42f
AD
133#include "timevar.h"
134
135/* See timevar.h for an explanation of timing variables. */
136
ea9ed226 137/* This macro evaluates to nonzero if timing variables are enabled. */
e22ad7fa 138#define TIMEVAR_ENABLE (timevar_report)
1509d42f
AD
139
140/* A timing variable. */
141
142struct timevar_def
143{
144 /* Elapsed time for this variable. */
145 struct timevar_time_def elapsed;
146
147 /* If this variable is timed independently of the timing stack,
148 using timevar_start, this contains the start time. */
149 struct timevar_time_def start_time;
150
151 /* The name of this timing variable. */
152 const char *name;
153
154 /* Non-zero if this timing variable is running as a standalone
155 timer. */
156 unsigned standalone : 1;
157
158 /* Non-zero if this timing variable was ever started or pushed onto
159 the timing stack. */
160 unsigned used : 1;
161};
162
163/* An element on the timing stack. Elapsed time is attributed to the
164 topmost timing variable on the stack. */
165
166struct timevar_stack_def
167{
168 /* The timing variable at this stack level. */
169 struct timevar_def *timevar;
170
171 /* The next lower timing variable context in the stack. */
172 struct timevar_stack_def *next;
173};
174
175/* Declared timing variables. Constructed from the contents of
176 timevar.def. */
177static struct timevar_def timevars[TIMEVAR_LAST];
178
179/* The top of the timing stack. */
180static struct timevar_stack_def *stack;
181
182/* A list of unused (i.e. allocated and subsequently popped)
183 timevar_stack_def instances. */
184static struct timevar_stack_def *unused_stack_instances;
185
186/* The time at which the topmost element on the timing stack was
187 pushed. Time elapsed since then is attributed to the topmost
188 element. */
189static struct timevar_time_def start_time;
190
126e3751
PE
191static void get_time (struct timevar_time_def *);
192static void timevar_accumulate (struct timevar_time_def *,
193 struct timevar_time_def *,
194 struct timevar_time_def *);
1509d42f
AD
195
196/* Fill the current times into TIME. The definition of this function
197 also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
ea9ed226 198 HAVE_WALL_TIME macros. */
1509d42f
AD
199
200static void
201get_time (now)
202 struct timevar_time_def *now;
203{
204 now->user = 0;
205 now->sys = 0;
206 now->wall = 0;
207
208 if (!TIMEVAR_ENABLE)
209 return;
210
211 {
212#ifdef USE_TIMES
213 struct tms tms;
ea9ed226 214 now->wall = times (&tms) * ticks_to_msec;
fdabfd76 215#if IN_GCC
ea9ed226
PE
216 now->user = tms.tms_utime * ticks_to_msec;
217 now->sys = tms.tms_stime * ticks_to_msec;
fdabfd76
PE
218#else
219 now->user = (tms.tms_utime + tms.tms_cutime) * ticks_to_msec;
220 now->sys = (tms.tms_stime + tms.tms_cstime) * ticks_to_msec;
221#endif
1509d42f
AD
222#endif
223#ifdef USE_GETRUSAGE
224 struct rusage rusage;
fdabfd76 225#if IN_GCC
1509d42f 226 getrusage (RUSAGE_SELF, &rusage);
fdabfd76
PE
227#else
228 getrusage (RUSAGE_CHILDREN, &rusage);
229#endif
1509d42f
AD
230 now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6;
231 now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6;
232#endif
233#ifdef USE_CLOCK
234 now->user = clock () * clocks_to_msec;
235#endif
236 }
237}
238
9e2c5ef1 239/* Add the difference between STOP and START to TIMER. */
1509d42f
AD
240
241static void
9e2c5ef1 242timevar_accumulate (timer, start, stop)
ea9ed226 243 struct timevar_time_def *timer;
9e2c5ef1
PE
244 struct timevar_time_def *start;
245 struct timevar_time_def *stop;
1509d42f 246{
9e2c5ef1
PE
247 timer->user += stop->user - start->user;
248 timer->sys += stop->sys - start->sys;
249 timer->wall += stop->wall - start->wall;
1509d42f
AD
250}
251
252/* Initialize timing variables. */
253
254void
255init_timevar ()
256{
257 if (!TIMEVAR_ENABLE)
258 return;
259
260 /* Zero all elapsed times. */
261 memset ((void *) timevars, 0, sizeof (timevars));
262
263 /* Initialize the names of timing variables. */
264#define DEFTIMEVAR(identifier__, name__) \
265 timevars[identifier__].name = name__;
266#include "timevar.def"
267#undef DEFTIMEVAR
268
269#ifdef USE_TIMES
270 ticks_to_msec = TICKS_TO_MSEC;
271#endif
272#ifdef USE_CLOCK
273 clocks_to_msec = CLOCKS_TO_MSEC;
274#endif
275}
276
277/* Push TIMEVAR onto the timing stack. No further elapsed time is
278 attributed to the previous topmost timing variable on the stack;
279 subsequent elapsed time is attributed to TIMEVAR, until it is
280 popped or another element is pushed on top.
281
282 TIMEVAR cannot be running as a standalone timer. */
283
284void
285timevar_push (timevar)
286 timevar_id_t timevar;
287{
288 struct timevar_def *tv = &timevars[timevar];
289 struct timevar_stack_def *context;
290 struct timevar_time_def now;
291
292 if (!TIMEVAR_ENABLE)
293 return;
294
295 /* Mark this timing variable as used. */
296 tv->used = 1;
297
298 /* Can't push a standalone timer. */
299 if (tv->standalone)
300 abort ();
301
302 /* What time is it? */
303 get_time (&now);
304
305 /* If the stack isn't empty, attribute the current elapsed time to
306 the old topmost element. */
307 if (stack)
308 timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
309
310 /* Reset the start time; from now on, time is attributed to
311 TIMEVAR. */
312 start_time = now;
313
314 /* See if we have a previously-allocated stack instance. If so,
315 take it off the list. If not, malloc a new one. */
316 if (unused_stack_instances != NULL)
317 {
318 context = unused_stack_instances;
319 unused_stack_instances = unused_stack_instances->next;
320 }
321 else
322 context = (struct timevar_stack_def *)
323 xmalloc (sizeof (struct timevar_stack_def));
324
325 /* Fill it in and put it on the stack. */
326 context->timevar = tv;
327 context->next = stack;
328 stack = context;
329}
330
331/* Pop the topmost timing variable element off the timing stack. The
332 popped variable must be TIMEVAR. Elapsed time since the that
333 element was pushed on, or since it was last exposed on top of the
334 stack when the element above it was popped off, is credited to that
335 timing variable. */
336
337void
338timevar_pop (timevar)
339 timevar_id_t timevar;
340{
341 struct timevar_time_def now;
342 struct timevar_stack_def *popped = stack;
343
344 if (!TIMEVAR_ENABLE)
345 return;
346
347 if (&timevars[timevar] != stack->timevar)
348 abort ();
349
350 /* What time is it? */
351 get_time (&now);
352
353 /* Attribute the elapsed time to the element we're popping. */
354 timevar_accumulate (&popped->timevar->elapsed, &start_time, &now);
355
356 /* Reset the start time; from now on, time is attributed to the
357 element just exposed on the stack. */
358 start_time = now;
359
360 /* Take the item off the stack. */
361 stack = stack->next;
362
363 /* Don't delete the stack element; instead, add it to the list of
364 unused elements for later use. */
365 popped->next = unused_stack_instances;
366 unused_stack_instances = popped;
367}
368
369/* Start timing TIMEVAR independently of the timing stack. Elapsed
370 time until timevar_stop is called for the same timing variable is
371 attributed to TIMEVAR. */
372
373void
374timevar_start (timevar)
375 timevar_id_t timevar;
376{
377 struct timevar_def *tv = &timevars[timevar];
378
379 if (!TIMEVAR_ENABLE)
380 return;
381
382 /* Mark this timing variable as used. */
383 tv->used = 1;
384
385 /* Don't allow the same timing variable to be started more than
386 once. */
387 if (tv->standalone)
388 abort ();
389 tv->standalone = 1;
390
391 get_time (&tv->start_time);
392}
393
394/* Stop timing TIMEVAR. Time elapsed since timevar_start was called
395 is attributed to it. */
396
397void
398timevar_stop (timevar)
399 timevar_id_t timevar;
400{
401 struct timevar_def *tv = &timevars[timevar];
402 struct timevar_time_def now;
403
404 if (!TIMEVAR_ENABLE)
405 return;
406
407 /* TIMEVAR must have been started via timevar_start. */
408 if (!tv->standalone)
409 abort ();
410
411 get_time (&now);
412 timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
413}
414
415/* Fill the elapsed time for TIMEVAR into ELAPSED. Returns
416 update-to-date information even if TIMEVAR is currently running. */
417
418void
419timevar_get (timevar, elapsed)
420 timevar_id_t timevar;
421 struct timevar_time_def *elapsed;
422{
423 struct timevar_def *tv = &timevars[timevar];
424 struct timevar_time_def now;
425
426 *elapsed = tv->elapsed;
427
428 /* Is TIMEVAR currently running as a standalone timer? */
429 if (tv->standalone)
430 {
431 get_time (&now);
432 timevar_accumulate (elapsed, &tv->start_time, &now);
433 }
434 /* Or is TIMEVAR at the top of the timer stack? */
435 else if (stack->timevar == tv)
436 {
437 get_time (&now);
438 timevar_accumulate (elapsed, &start_time, &now);
439 }
440}
441
442/* Summarize timing variables to FP. The timing variable TV_TOTAL has
443 a special meaning -- it's considered to be the total elapsed time,
444 for normalizing the others, and is displayed last. */
445
446void
447timevar_print (fp)
448 FILE *fp;
449{
450 /* Only print stuff if we have some sort of time information. */
451#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME)
452 unsigned int /* timevar_id_t */ id;
453 struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed;
454 struct timevar_time_def now;
455
456 if (!TIMEVAR_ENABLE)
457 return;
458
459 /* Update timing information in case we're calling this from GDB. */
460
461 if (fp == 0)
462 fp = stderr;
463
464 /* What time is it? */
465 get_time (&now);
466
467 /* If the stack isn't empty, attribute the current elapsed time to
468 the old topmost element. */
469 if (stack)
470 timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
471
472 /* Reset the start time; from now on, time is attributed to
473 TIMEVAR. */
474 start_time = now;
475
476 fputs (_("\nExecution times (seconds)\n"), fp);
477 for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
478 {
479 struct timevar_def *tv = &timevars[(timevar_id_t) id];
480 const float tiny = 5e-3;
481
482 /* Don't print the total execution time here; that goes at the
483 end. */
484 if ((timevar_id_t) id == TV_TOTAL)
485 continue;
486
487 /* Don't print timing variables that were never used. */
488 if (!tv->used)
489 continue;
490
491 /* Don't print timing variables if we're going to get a row of
492 zeroes. */
493 if (tv->elapsed.user < tiny
494 && tv->elapsed.sys < tiny
495 && tv->elapsed.wall < tiny)
496 continue;
497
498 /* The timing variable name. */
499 fprintf (fp, " %-22s:", tv->name);
500
501#ifdef HAVE_USER_TIME
502 /* Print user-mode time for this process. */
503 fprintf (fp, "%7.2f (%2.0f%%) usr",
504 tv->elapsed.user,
505 (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
506#endif /* HAVE_USER_TIME */
507
508#ifdef HAVE_SYS_TIME
509 /* Print system-mode time for this process. */
510 fprintf (fp, "%7.2f (%2.0f%%) sys",
511 tv->elapsed.sys,
512 (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
513#endif /* HAVE_SYS_TIME */
514
515#ifdef HAVE_WALL_TIME
516 /* Print wall clock time elapsed. */
517 fprintf (fp, "%7.2f (%2.0f%%) wall",
518 tv->elapsed.wall,
519 (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
520#endif /* HAVE_WALL_TIME */
521
522 putc ('\n', fp);
523 }
524
525 /* Print total time. */
526 fputs (_(" TOTAL :"), fp);
527#ifdef HAVE_USER_TIME
528 fprintf (fp, "%7.2f ", total->user);
529#endif
530#ifdef HAVE_SYS_TIME
531 fprintf (fp, "%7.2f ", total->sys);
532#endif
533#ifdef HAVE_WALL_TIME
534 fprintf (fp, "%7.2f\n", total->wall);
535#endif
536
537#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME)
538 || defined (HAVE_WALL_TIME) */
539}
540
541/* Returns time (user + system) used so far by the compiler process,
542 in microseconds. */
543
544long
545get_run_time ()
546{
547 struct timevar_time_def total_elapsed;
548 timevar_get (TV_TOTAL, &total_elapsed);
549 return total_elapsed.user + total_elapsed.sys;
550}
551
552/* Prints a message to stderr stating that time elapsed in STR is
553 TOTAL (given in microseconds). */
554
555void
556print_time (str, total)
557 const char *str;
558 long total;
559{
560 long all_time = get_run_time ();
561 fprintf (stderr,
562 _("time in %s: %ld.%06ld (%ld%%)\n"),
563 str, total / 1000000, total % 1000000,
ea9ed226
PE
564 all_time == 0 ? 0
565 : (long) (((100.0 * (double) total) / (double) all_time) + .5));
1509d42f 566}