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