]> git.saurik.com Git - bison.git/blame - lib/timevar.c
Sync with latest FSF version.
[bison.git] / lib / timevar.c
CommitLineData
1509d42f 1/* Timing variables for measuring compiler performance.
fdabfd76 2 Copyright (C) 2000, 2002 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
1509d42f
AD
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
fdabfd76
PE
22#if IN_GCC
23
1509d42f
AD
24#include "config.h"
25#include "system.h"
26#include "intl.h"
27#include "rtl.h"
28
fdabfd76
PE
29#else
30
31/* This source file is taken from the GCC source code, with slight
32 modifications that are under control of the IN_GCC preprocessor
33 variable. The !IN_GCC part of this file is specific to Bison. */
34
35# include "../src/system.h"
36# if HAVE_SYS_TIME_H
37# include <sys/time.h>
38# endif
e22ad7fa 39int timevar_report = 0;
fdabfd76
PE
40
41#endif
42
43
1509d42f
AD
44#ifdef HAVE_SYS_TIMES_H
45# include <sys/times.h>
46#endif
47#ifdef HAVE_SYS_RESOURCE_H
48#include <sys/resource.h>
49#endif
50
51#ifndef HAVE_CLOCK_T
52typedef int clock_t;
53#endif
54
55#ifndef HAVE_STRUCT_TMS
56struct tms
57{
58 clock_t tms_utime;
59 clock_t tms_stime;
60 clock_t tms_cutime;
61 clock_t tms_cstime;
62};
63#endif
64
65#if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
66extern int getrusage PARAMS ((int, struct rusage *));
67#endif
68#if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
69extern clock_t times PARAMS ((struct tms *));
70#endif
71#if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
72extern clock_t clock PARAMS ((void));
73#endif
74
75#ifndef RUSAGE_SELF
76# define RUSAGE_SELF 0
77#endif
78
79/* Calculation of scale factor to convert ticks to microseconds.
80 We mustn't use CLOCKS_PER_SEC except with clock(). */
81#if HAVE_SYSCONF && defined _SC_CLK_TCK
82# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
83#else
84# ifdef CLK_TCK
85# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
86# else
87# ifdef HZ
88# define TICKS_PER_SECOND HZ /* traditional UNIX */
89# else
90# define TICKS_PER_SECOND 100 /* often the correct value */
91# endif
92# endif
93#endif
94
95/* Prefer times to getrusage to clock (each gives successively less
96 information). */
97#ifdef HAVE_TIMES
98# define USE_TIMES
99# define HAVE_USER_TIME
100# define HAVE_SYS_TIME
101# define HAVE_WALL_TIME
102#else
103#ifdef HAVE_GETRUSAGE
104# define USE_GETRUSAGE
105# define HAVE_USER_TIME
106# define HAVE_SYS_TIME
107#else
108#ifdef HAVE_CLOCK
109# define USE_CLOCK
110# define HAVE_USER_TIME
111#endif
112#endif
113#endif
114
115/* libc is very likely to have snuck a call to sysconf() into one of
116 the underlying constants, and that can be very slow, so we have to
117 precompute them. Whose wonderful idea was it to make all those
118 _constants_ variable at run time, anyway? */
119#ifdef USE_TIMES
120static float ticks_to_msec;
9e2c5ef1 121#define TICKS_TO_MSEC (1.0 / TICKS_PER_SECOND)
1509d42f
AD
122#endif
123
124#ifdef USE_CLOCK
125static float clocks_to_msec;
9e2c5ef1 126#define CLOCKS_TO_MSEC (1.0 / CLOCKS_PER_SEC)
1509d42f
AD
127#endif
128
fdabfd76 129#if IN_GCC
1509d42f 130#include "flags.h"
fdabfd76 131#endif
1509d42f
AD
132#include "timevar.h"
133
134/* See timevar.h for an explanation of timing variables. */
135
ea9ed226 136/* This macro evaluates to nonzero if timing variables are enabled. */
e22ad7fa 137#define TIMEVAR_ENABLE (timevar_report)
1509d42f
AD
138
139/* A timing variable. */
140
141struct timevar_def
142{
143 /* Elapsed time for this variable. */
144 struct timevar_time_def elapsed;
145
146 /* If this variable is timed independently of the timing stack,
147 using timevar_start, this contains the start time. */
148 struct timevar_time_def start_time;
149
150 /* The name of this timing variable. */
151 const char *name;
152
153 /* Non-zero if this timing variable is running as a standalone
154 timer. */
155 unsigned standalone : 1;
156
157 /* Non-zero if this timing variable was ever started or pushed onto
158 the timing stack. */
159 unsigned used : 1;
160};
161
162/* An element on the timing stack. Elapsed time is attributed to the
163 topmost timing variable on the stack. */
164
165struct timevar_stack_def
166{
167 /* The timing variable at this stack level. */
168 struct timevar_def *timevar;
169
170 /* The next lower timing variable context in the stack. */
171 struct timevar_stack_def *next;
172};
173
174/* Declared timing variables. Constructed from the contents of
175 timevar.def. */
176static struct timevar_def timevars[TIMEVAR_LAST];
177
178/* The top of the timing stack. */
179static struct timevar_stack_def *stack;
180
181/* A list of unused (i.e. allocated and subsequently popped)
182 timevar_stack_def instances. */
183static struct timevar_stack_def *unused_stack_instances;
184
185/* The time at which the topmost element on the timing stack was
186 pushed. Time elapsed since then is attributed to the topmost
187 element. */
188static struct timevar_time_def start_time;
189
190static void get_time
191 PARAMS ((struct timevar_time_def *));
192static void timevar_accumulate
193 PARAMS ((struct timevar_time_def *, struct timevar_time_def *,
194 struct timevar_time_def *));
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}