]> git.saurik.com Git - bison.git/blob - lib/timevar.c
Update copyright.
[bison.git] / lib / timevar.c
1 /* Timing variables for measuring compiler performance.
2 Copyright (C) 2000, 2002, 2004, 2005 Free Software Foundation, Inc.
3 Contributed by Alex Samuel <samuel@codesourcery.com>
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 Bison is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bison is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bison; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
22 #include "config.h"
23
24 #if IN_GCC
25
26 #include "system.h"
27 #include "intl.h"
28 #include "rtl.h"
29
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. */
35
36 # include "../src/system.h"
37 # if HAVE_SYS_TIME_H
38 # include <sys/time.h>
39 # endif
40 int timevar_report = 0;
41
42 #endif
43
44
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
53 typedef int clock_t;
54 #endif
55
56 #ifndef HAVE_STRUCT_TMS
57 struct 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
67 extern int getrusage (int, struct rusage *);
68 #endif
69 #if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
70 extern clock_t times (struct tms *);
71 #endif
72 #if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
73 extern clock_t clock (void);
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
121 static float ticks_to_msec;
122 #define TICKS_TO_MSEC (1.0 / TICKS_PER_SECOND)
123 #endif
124
125 #ifdef USE_CLOCK
126 static float clocks_to_msec;
127 #define CLOCKS_TO_MSEC (1.0 / CLOCKS_PER_SEC)
128 #endif
129
130 #if IN_GCC
131 #include "flags.h"
132 #endif
133 #include "timevar.h"
134
135 /* See timevar.h for an explanation of timing variables. */
136
137 /* This macro evaluates to nonzero if timing variables are enabled. */
138 #define TIMEVAR_ENABLE (timevar_report)
139
140 /* A timing variable. */
141
142 struct 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
166 struct 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. */
177 static struct timevar_def timevars[TIMEVAR_LAST];
178
179 /* The top of the timing stack. */
180 static struct timevar_stack_def *stack;
181
182 /* A list of unused (i.e. allocated and subsequently popped)
183 timevar_stack_def instances. */
184 static 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. */
189 static struct timevar_time_def start_time;
190
191 static void get_time (struct timevar_time_def *);
192 static void timevar_accumulate (struct timevar_time_def *,
193 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
198 HAVE_WALL_TIME macros. */
199
200 static void
201 get_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;
214 now->wall = times (&tms) * ticks_to_msec;
215 #if IN_GCC
216 now->user = tms.tms_utime * ticks_to_msec;
217 now->sys = tms.tms_stime * ticks_to_msec;
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
222 #endif
223 #ifdef USE_GETRUSAGE
224 struct rusage rusage;
225 #if IN_GCC
226 getrusage (RUSAGE_SELF, &rusage);
227 #else
228 getrusage (RUSAGE_CHILDREN, &rusage);
229 #endif
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
239 /* Add the difference between STOP and START to TIMER. */
240
241 static void
242 timevar_accumulate (timer, start, stop)
243 struct timevar_time_def *timer;
244 struct timevar_time_def *start;
245 struct timevar_time_def *stop;
246 {
247 timer->user += stop->user - start->user;
248 timer->sys += stop->sys - start->sys;
249 timer->wall += stop->wall - start->wall;
250 }
251
252 /* Initialize timing variables. */
253
254 void
255 init_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
284 void
285 timevar_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
337 void
338 timevar_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
373 void
374 timevar_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
397 void
398 timevar_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
418 void
419 timevar_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
446 void
447 timevar_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
544 long
545 get_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
555 void
556 print_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,
564 all_time == 0 ? 0
565 : (long) (((100.0 * (double) total) / (double) all_time) + .5));
566 }