timevar.c revision 132718
190075Sobrien/* Timing variables for measuring compiler performance.
2132718Skan   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
390075Sobrien   Contributed by Alex Samuel <samuel@codesourcery.com>
490075Sobrien
590075SobrienThis file is part of GCC.
690075Sobrien
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1190075Sobrien
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1690075Sobrien
1790075SobrienYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2190075Sobrien
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
2490075Sobrien#ifdef HAVE_SYS_TIMES_H
2590075Sobrien# include <sys/times.h>
2690075Sobrien#endif
2790075Sobrien#ifdef HAVE_SYS_RESOURCE_H
2890075Sobrien#include <sys/resource.h>
2990075Sobrien#endif
30132718Skan#include "coretypes.h"
31132718Skan#include "tm.h"
32132718Skan#include "intl.h"
33132718Skan#include "rtl.h"
34132718Skan#include "toplev.h"
3590075Sobrien
3690075Sobrien#ifndef HAVE_CLOCK_T
3790075Sobrientypedef int clock_t;
3890075Sobrien#endif
3990075Sobrien
4090075Sobrien#ifndef HAVE_STRUCT_TMS
4190075Sobrienstruct tms
4290075Sobrien{
4390075Sobrien  clock_t tms_utime;
4490075Sobrien  clock_t tms_stime;
4590075Sobrien  clock_t tms_cutime;
4690075Sobrien  clock_t tms_cstime;
4790075Sobrien};
4890075Sobrien#endif
4990075Sobrien
5090075Sobrien#ifndef RUSAGE_SELF
5190075Sobrien# define RUSAGE_SELF 0
5290075Sobrien#endif
5390075Sobrien
5490075Sobrien/* Calculation of scale factor to convert ticks to microseconds.
5590075Sobrien   We mustn't use CLOCKS_PER_SEC except with clock().  */
5690075Sobrien#if HAVE_SYSCONF && defined _SC_CLK_TCK
5790075Sobrien# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
5890075Sobrien#else
5990075Sobrien# ifdef CLK_TCK
6090075Sobrien#  define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
6190075Sobrien# else
6290075Sobrien#  ifdef HZ
6390075Sobrien#   define TICKS_PER_SECOND HZ  /* traditional UNIX */
6490075Sobrien#  else
6590075Sobrien#   define TICKS_PER_SECOND 100 /* often the correct value */
6690075Sobrien#  endif
6790075Sobrien# endif
6890075Sobrien#endif
6990075Sobrien
7090075Sobrien/* Prefer times to getrusage to clock (each gives successively less
7190075Sobrien   information).  */
7290075Sobrien#ifdef HAVE_TIMES
73132718Skan# if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
74132718Skan  extern clock_t times (struct tms *);
75132718Skan# endif
7690075Sobrien# define USE_TIMES
7790075Sobrien# define HAVE_USER_TIME
7890075Sobrien# define HAVE_SYS_TIME
7990075Sobrien# define HAVE_WALL_TIME
8090075Sobrien#else
8190075Sobrien#ifdef HAVE_GETRUSAGE
82132718Skan# if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
83132718Skan  extern int getrusage (int, struct rusage *);
84132718Skan# endif
8590075Sobrien# define USE_GETRUSAGE
8690075Sobrien# define HAVE_USER_TIME
8790075Sobrien# define HAVE_SYS_TIME
8890075Sobrien#else
8990075Sobrien#ifdef HAVE_CLOCK
90132718Skan# if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
91132718Skan  extern clock_t clock (void);
92132718Skan# endif
9390075Sobrien# define USE_CLOCK
9490075Sobrien# define HAVE_USER_TIME
9590075Sobrien#endif
9690075Sobrien#endif
9790075Sobrien#endif
9890075Sobrien
9990075Sobrien/* libc is very likely to have snuck a call to sysconf() into one of
10090075Sobrien   the underlying constants, and that can be very slow, so we have to
10190075Sobrien   precompute them.  Whose wonderful idea was it to make all those
10290075Sobrien   _constants_ variable at run time, anyway?  */
10390075Sobrien#ifdef USE_TIMES
104132718Skanstatic double ticks_to_msec;
105132718Skan#define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND)
10690075Sobrien#endif
10790075Sobrien
10890075Sobrien#ifdef USE_CLOCK
109132718Skanstatic double clocks_to_msec;
110132718Skan#define CLOCKS_TO_MSEC (1 / (double)CLOCKS_PER_SEC)
11190075Sobrien#endif
11290075Sobrien
11390075Sobrien#include "flags.h"
11490075Sobrien#include "timevar.h"
11590075Sobrien
116132718Skanstatic bool timevar_enable;
117132718Skan
11890075Sobrien/* See timevar.h for an explanation of timing variables.  */
11990075Sobrien
12090075Sobrien/* A timing variable.  */
12190075Sobrien
12290075Sobrienstruct timevar_def
12390075Sobrien{
12490075Sobrien  /* Elapsed time for this variable.  */
12590075Sobrien  struct timevar_time_def elapsed;
12690075Sobrien
12790075Sobrien  /* If this variable is timed independently of the timing stack,
12890075Sobrien     using timevar_start, this contains the start time.  */
12990075Sobrien  struct timevar_time_def start_time;
13090075Sobrien
13190075Sobrien  /* The name of this timing variable.  */
13290075Sobrien  const char *name;
13390075Sobrien
134132718Skan  /* Nonzero if this timing variable is running as a standalone
13590075Sobrien     timer.  */
13690075Sobrien  unsigned standalone : 1;
13790075Sobrien
138132718Skan  /* Nonzero if this timing variable was ever started or pushed onto
13990075Sobrien     the timing stack.  */
14090075Sobrien  unsigned used : 1;
14190075Sobrien};
14290075Sobrien
14390075Sobrien/* An element on the timing stack.  Elapsed time is attributed to the
14490075Sobrien   topmost timing variable on the stack.  */
14590075Sobrien
14690075Sobrienstruct timevar_stack_def
14790075Sobrien{
14890075Sobrien  /* The timing variable at this stack level.  */
14990075Sobrien  struct timevar_def *timevar;
15090075Sobrien
15190075Sobrien  /* The next lower timing variable context in the stack.  */
15290075Sobrien  struct timevar_stack_def *next;
15390075Sobrien};
15490075Sobrien
15590075Sobrien/* Declared timing variables.  Constructed from the contents of
15690075Sobrien   timevar.def.  */
15790075Sobrienstatic struct timevar_def timevars[TIMEVAR_LAST];
15890075Sobrien
15990075Sobrien/* The top of the timing stack.  */
16090075Sobrienstatic struct timevar_stack_def *stack;
16190075Sobrien
16290075Sobrien/* A list of unused (i.e. allocated and subsequently popped)
16390075Sobrien   timevar_stack_def instances.  */
16490075Sobrienstatic struct timevar_stack_def *unused_stack_instances;
16590075Sobrien
16690075Sobrien/* The time at which the topmost element on the timing stack was
16790075Sobrien   pushed.  Time elapsed since then is attributed to the topmost
16890075Sobrien   element.  */
16990075Sobrienstatic struct timevar_time_def start_time;
17090075Sobrien
171132718Skanstatic void get_time (struct timevar_time_def *);
172132718Skanstatic void timevar_accumulate (struct timevar_time_def *,
173132718Skan				struct timevar_time_def *,
174132718Skan				struct timevar_time_def *);
17590075Sobrien
17690075Sobrien/* Fill the current times into TIME.  The definition of this function
17790075Sobrien   also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
178117395Skan   HAVE_WALL_TIME macros.  */
17990075Sobrien
18090075Sobrienstatic void
181132718Skanget_time (struct timevar_time_def *now)
18290075Sobrien{
18390075Sobrien  now->user = 0;
18490075Sobrien  now->sys  = 0;
18590075Sobrien  now->wall = 0;
18690075Sobrien
187132718Skan  if (!timevar_enable)
18890075Sobrien    return;
18990075Sobrien
19090075Sobrien  {
19190075Sobrien#ifdef USE_TIMES
19290075Sobrien    struct tms tms;
19390075Sobrien    now->wall = times (&tms)  * ticks_to_msec;
19490075Sobrien    now->user = tms.tms_utime * ticks_to_msec;
19590075Sobrien    now->sys  = tms.tms_stime * ticks_to_msec;
19690075Sobrien#endif
19790075Sobrien#ifdef USE_GETRUSAGE
19890075Sobrien    struct rusage rusage;
19990075Sobrien    getrusage (RUSAGE_SELF, &rusage);
20090075Sobrien    now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6;
20190075Sobrien    now->sys  = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6;
20290075Sobrien#endif
20390075Sobrien#ifdef USE_CLOCK
20490075Sobrien    now->user = clock () * clocks_to_msec;
20590075Sobrien#endif
20690075Sobrien  }
20790075Sobrien}
20890075Sobrien
20990075Sobrien/* Add the difference between STOP_TIME and START_TIME to TIMER.  */
21090075Sobrien
211117395Skanstatic void
212132718Skantimevar_accumulate (struct timevar_time_def *timer,
213132718Skan		    struct timevar_time_def *start_time,
214132718Skan		    struct timevar_time_def *stop_time)
21590075Sobrien{
21690075Sobrien  timer->user += stop_time->user - start_time->user;
21790075Sobrien  timer->sys += stop_time->sys - start_time->sys;
21890075Sobrien  timer->wall += stop_time->wall - start_time->wall;
21990075Sobrien}
22090075Sobrien
22190075Sobrien/* Initialize timing variables.  */
22290075Sobrien
22390075Sobrienvoid
224132718Skantimevar_init (void)
22590075Sobrien{
226132718Skan  timevar_enable = true;
22790075Sobrien
22890075Sobrien  /* Zero all elapsed times.  */
229132718Skan  memset (timevars, 0, sizeof (timevars));
23090075Sobrien
23190075Sobrien  /* Initialize the names of timing variables.  */
23290075Sobrien#define DEFTIMEVAR(identifier__, name__) \
23390075Sobrien  timevars[identifier__].name = name__;
23490075Sobrien#include "timevar.def"
23590075Sobrien#undef DEFTIMEVAR
23690075Sobrien
23790075Sobrien#ifdef USE_TIMES
23890075Sobrien  ticks_to_msec = TICKS_TO_MSEC;
23990075Sobrien#endif
24090075Sobrien#ifdef USE_CLOCK
24190075Sobrien  clocks_to_msec = CLOCKS_TO_MSEC;
24290075Sobrien#endif
24390075Sobrien}
24490075Sobrien
24590075Sobrien/* Push TIMEVAR onto the timing stack.  No further elapsed time is
24690075Sobrien   attributed to the previous topmost timing variable on the stack;
24790075Sobrien   subsequent elapsed time is attributed to TIMEVAR, until it is
248117395Skan   popped or another element is pushed on top.
24990075Sobrien
25090075Sobrien   TIMEVAR cannot be running as a standalone timer.  */
25190075Sobrien
25290075Sobrienvoid
253132718Skantimevar_push (timevar_id_t timevar)
25490075Sobrien{
25590075Sobrien  struct timevar_def *tv = &timevars[timevar];
25690075Sobrien  struct timevar_stack_def *context;
25790075Sobrien  struct timevar_time_def now;
25890075Sobrien
259132718Skan  if (!timevar_enable)
26090075Sobrien    return;
26190075Sobrien
26290075Sobrien  /* Mark this timing variable as used.  */
26390075Sobrien  tv->used = 1;
26490075Sobrien
26590075Sobrien  /* Can't push a standalone timer.  */
26690075Sobrien  if (tv->standalone)
26790075Sobrien    abort ();
26890075Sobrien
26990075Sobrien  /* What time is it?  */
27090075Sobrien  get_time (&now);
27190075Sobrien
27290075Sobrien  /* If the stack isn't empty, attribute the current elapsed time to
27390075Sobrien     the old topmost element.  */
27490075Sobrien  if (stack)
27590075Sobrien    timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
27690075Sobrien
27790075Sobrien  /* Reset the start time; from now on, time is attributed to
27890075Sobrien     TIMEVAR.  */
27990075Sobrien  start_time = now;
28090075Sobrien
28190075Sobrien  /* See if we have a previously-allocated stack instance.  If so,
28290075Sobrien     take it off the list.  If not, malloc a new one.  */
283117395Skan  if (unused_stack_instances != NULL)
28490075Sobrien    {
28590075Sobrien      context = unused_stack_instances;
28690075Sobrien      unused_stack_instances = unused_stack_instances->next;
28790075Sobrien    }
28890075Sobrien  else
289132718Skan    context = xmalloc (sizeof (struct timevar_stack_def));
29090075Sobrien
29190075Sobrien  /* Fill it in and put it on the stack.  */
29290075Sobrien  context->timevar = tv;
29390075Sobrien  context->next = stack;
29490075Sobrien  stack = context;
29590075Sobrien}
29690075Sobrien
29790075Sobrien/* Pop the topmost timing variable element off the timing stack.  The
29890075Sobrien   popped variable must be TIMEVAR.  Elapsed time since the that
29990075Sobrien   element was pushed on, or since it was last exposed on top of the
30090075Sobrien   stack when the element above it was popped off, is credited to that
30190075Sobrien   timing variable.  */
30290075Sobrien
30390075Sobrienvoid
304132718Skantimevar_pop (timevar_id_t timevar)
30590075Sobrien{
30690075Sobrien  struct timevar_time_def now;
30790075Sobrien  struct timevar_stack_def *popped = stack;
30890075Sobrien
309132718Skan  if (!timevar_enable)
31090075Sobrien    return;
31190075Sobrien
31290075Sobrien  if (&timevars[timevar] != stack->timevar)
313117395Skan    {
314117395Skan      sorry ("cannot timevar_pop '%s' when top of timevars stack is '%s'",
315117395Skan             timevars[timevar].name, stack->timevar->name);
316117395Skan      abort ();
317117395Skan    }
31890075Sobrien
31990075Sobrien  /* What time is it?  */
32090075Sobrien  get_time (&now);
32190075Sobrien
32290075Sobrien  /* Attribute the elapsed time to the element we're popping.  */
32390075Sobrien  timevar_accumulate (&popped->timevar->elapsed, &start_time, &now);
32490075Sobrien
32590075Sobrien  /* Reset the start time; from now on, time is attributed to the
32690075Sobrien     element just exposed on the stack.  */
32790075Sobrien  start_time = now;
32890075Sobrien
32990075Sobrien  /* Take the item off the stack.  */
33090075Sobrien  stack = stack->next;
33190075Sobrien
33290075Sobrien  /* Don't delete the stack element; instead, add it to the list of
33390075Sobrien     unused elements for later use.  */
33490075Sobrien  popped->next = unused_stack_instances;
33590075Sobrien  unused_stack_instances = popped;
33690075Sobrien}
33790075Sobrien
33890075Sobrien/* Start timing TIMEVAR independently of the timing stack.  Elapsed
33990075Sobrien   time until timevar_stop is called for the same timing variable is
34090075Sobrien   attributed to TIMEVAR.  */
34190075Sobrien
34290075Sobrienvoid
343132718Skantimevar_start (timevar_id_t timevar)
34490075Sobrien{
34590075Sobrien  struct timevar_def *tv = &timevars[timevar];
34690075Sobrien
347132718Skan  if (!timevar_enable)
34890075Sobrien    return;
34990075Sobrien
35090075Sobrien  /* Mark this timing variable as used.  */
35190075Sobrien  tv->used = 1;
35290075Sobrien
35390075Sobrien  /* Don't allow the same timing variable to be started more than
35490075Sobrien     once.  */
35590075Sobrien  if (tv->standalone)
35690075Sobrien    abort ();
35790075Sobrien  tv->standalone = 1;
35890075Sobrien
35990075Sobrien  get_time (&tv->start_time);
36090075Sobrien}
36190075Sobrien
36290075Sobrien/* Stop timing TIMEVAR.  Time elapsed since timevar_start was called
36390075Sobrien   is attributed to it.  */
36490075Sobrien
36590075Sobrienvoid
366132718Skantimevar_stop (timevar_id_t timevar)
36790075Sobrien{
36890075Sobrien  struct timevar_def *tv = &timevars[timevar];
36990075Sobrien  struct timevar_time_def now;
37090075Sobrien
371132718Skan  if (!timevar_enable)
37290075Sobrien    return;
37390075Sobrien
37490075Sobrien  /* TIMEVAR must have been started via timevar_start.  */
37590075Sobrien  if (!tv->standalone)
37690075Sobrien    abort ();
37790075Sobrien
37890075Sobrien  get_time (&now);
37990075Sobrien  timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
38090075Sobrien}
38190075Sobrien
38290075Sobrien/* Fill the elapsed time for TIMEVAR into ELAPSED.  Returns
38390075Sobrien   update-to-date information even if TIMEVAR is currently running.  */
38490075Sobrien
38590075Sobrienvoid
386132718Skantimevar_get (timevar_id_t timevar, struct timevar_time_def *elapsed)
38790075Sobrien{
38890075Sobrien  struct timevar_def *tv = &timevars[timevar];
38990075Sobrien  struct timevar_time_def now;
39090075Sobrien
39190075Sobrien  *elapsed = tv->elapsed;
392117395Skan
39390075Sobrien  /* Is TIMEVAR currently running as a standalone timer?  */
39490075Sobrien  if (tv->standalone)
39590075Sobrien    {
39690075Sobrien      get_time (&now);
39790075Sobrien      timevar_accumulate (elapsed, &tv->start_time, &now);
39890075Sobrien    }
39990075Sobrien  /* Or is TIMEVAR at the top of the timer stack?  */
40090075Sobrien  else if (stack->timevar == tv)
40190075Sobrien    {
40290075Sobrien      get_time (&now);
40390075Sobrien      timevar_accumulate (elapsed, &start_time, &now);
40490075Sobrien    }
40590075Sobrien}
40690075Sobrien
40790075Sobrien/* Summarize timing variables to FP.  The timing variable TV_TOTAL has
40890075Sobrien   a special meaning -- it's considered to be the total elapsed time,
40990075Sobrien   for normalizing the others, and is displayed last.  */
41090075Sobrien
41190075Sobrienvoid
412132718Skantimevar_print (FILE *fp)
41390075Sobrien{
41490075Sobrien  /* Only print stuff if we have some sort of time information.  */
41590075Sobrien#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME)
41690075Sobrien  unsigned int /* timevar_id_t */ id;
41790075Sobrien  struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed;
41890075Sobrien  struct timevar_time_def now;
41990075Sobrien
420132718Skan  if (!timevar_enable)
42190075Sobrien    return;
42290075Sobrien
42390075Sobrien  /* Update timing information in case we're calling this from GDB.  */
42490075Sobrien
42590075Sobrien  if (fp == 0)
42690075Sobrien    fp = stderr;
42790075Sobrien
42890075Sobrien  /* What time is it?  */
42990075Sobrien  get_time (&now);
43090075Sobrien
43190075Sobrien  /* If the stack isn't empty, attribute the current elapsed time to
43290075Sobrien     the old topmost element.  */
43390075Sobrien  if (stack)
43490075Sobrien    timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
43590075Sobrien
43690075Sobrien  /* Reset the start time; from now on, time is attributed to
43790075Sobrien     TIMEVAR.  */
43890075Sobrien  start_time = now;
43990075Sobrien
44090075Sobrien  fputs (_("\nExecution times (seconds)\n"), fp);
44190075Sobrien  for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
44290075Sobrien    {
44390075Sobrien      struct timevar_def *tv = &timevars[(timevar_id_t) id];
444132718Skan      const double tiny = 5e-3;
44590075Sobrien
44690075Sobrien      /* Don't print the total execution time here; that goes at the
44790075Sobrien	 end.  */
44890075Sobrien      if ((timevar_id_t) id == TV_TOTAL)
44990075Sobrien	continue;
45090075Sobrien
45190075Sobrien      /* Don't print timing variables that were never used.  */
45290075Sobrien      if (!tv->used)
45390075Sobrien	continue;
45490075Sobrien
45590075Sobrien      /* Don't print timing variables if we're going to get a row of
45690075Sobrien         zeroes.  */
45790075Sobrien      if (tv->elapsed.user < tiny
45890075Sobrien	  && tv->elapsed.sys < tiny
45990075Sobrien	  && tv->elapsed.wall < tiny)
46090075Sobrien	continue;
46190075Sobrien
46290075Sobrien      /* The timing variable name.  */
46390075Sobrien      fprintf (fp, " %-22s:", tv->name);
46490075Sobrien
46590075Sobrien#ifdef HAVE_USER_TIME
46690075Sobrien      /* Print user-mode time for this process.  */
467117395Skan      fprintf (fp, "%7.2f (%2.0f%%) usr",
46890075Sobrien	       tv->elapsed.user,
46990075Sobrien	       (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
47090075Sobrien#endif /* HAVE_USER_TIME */
47190075Sobrien
47290075Sobrien#ifdef HAVE_SYS_TIME
47390075Sobrien      /* Print system-mode time for this process.  */
474117395Skan      fprintf (fp, "%7.2f (%2.0f%%) sys",
47590075Sobrien	       tv->elapsed.sys,
47690075Sobrien	       (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
47790075Sobrien#endif /* HAVE_SYS_TIME */
47890075Sobrien
47990075Sobrien#ifdef HAVE_WALL_TIME
48090075Sobrien      /* Print wall clock time elapsed.  */
481117395Skan      fprintf (fp, "%7.2f (%2.0f%%) wall",
48290075Sobrien	       tv->elapsed.wall,
48390075Sobrien	       (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
48490075Sobrien#endif /* HAVE_WALL_TIME */
48590075Sobrien
48690075Sobrien      putc ('\n', fp);
48790075Sobrien    }
48890075Sobrien
48990075Sobrien  /* Print total time.  */
49090075Sobrien  fputs (_(" TOTAL                 :"), fp);
49190075Sobrien#ifdef HAVE_USER_TIME
49290075Sobrien  fprintf (fp, "%7.2f          ", total->user);
493117395Skan#endif
49490075Sobrien#ifdef HAVE_SYS_TIME
49590075Sobrien  fprintf (fp, "%7.2f          ", total->sys);
49690075Sobrien#endif
49790075Sobrien#ifdef HAVE_WALL_TIME
49890075Sobrien  fprintf (fp, "%7.2f\n", total->wall);
49990075Sobrien#endif
500117395Skan
501117395Skan#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME)
50290075Sobrien	  || defined (HAVE_WALL_TIME) */
50390075Sobrien}
50490075Sobrien
50590075Sobrien/* Prints a message to stderr stating that time elapsed in STR is
50690075Sobrien   TOTAL (given in microseconds).  */
50790075Sobrien
50890075Sobrienvoid
509132718Skanprint_time (const char *str, long total)
51090075Sobrien{
51190075Sobrien  long all_time = get_run_time ();
51290075Sobrien  fprintf (stderr,
51390075Sobrien	   _("time in %s: %ld.%06ld (%ld%%)\n"),
51490075Sobrien	   str, total / 1000000, total % 1000000,
515117395Skan	   all_time == 0 ? 0
516117395Skan	   : (long) (((100.0 * (double) total) / (double) all_time) + .5));
51790075Sobrien}
518