(root)/
bison-3.8.2/
lib/
timevar.c
       1  /* Timing variables for measuring compiler performance.
       2  
       3     Copyright (C) 2000, 2002, 2004, 2006, 2009-2015, 2018-2021 Free Software
       4     Foundation, Inc.
       5  
       6     Contributed by Alex Samuel <samuel@codesourcery.com>
       7  
       8     This program is free software: you can redistribute it and/or modify
       9     it under the terms of the GNU General Public License as published by
      10     the Free Software Foundation, either version 3 of the License, or
      11     (at your option) any later version.
      12  
      13     This program is distributed in the hope that it will be useful,
      14     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16     GNU General Public License for more details.
      17  
      18     You should have received a copy of the GNU General Public License
      19     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      20  
      21  #include <config.h>
      22  
      23  /* Specification.  */
      24  #include "timevar.h"
      25  
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  #include <sys/resource.h>
      30  #include <sys/time.h>
      31  #include <sys/times.h>
      32  
      33  #include "gethrxtime.h"
      34  #include "gettext.h"
      35  #define _(msgid) gettext (msgid)
      36  #include "xalloc.h"
      37  
      38  /* See timevar.h for an explanation of timing variables.  */
      39  
      40  int timevar_enabled = 0;
      41  
      42  /* A timing variable.  */
      43  
      44  struct timevar_def
      45  {
      46    /* Elapsed time for this variable.  */
      47    struct timevar_time_def elapsed;
      48  
      49    /* If this variable is timed independently of the timing stack,
      50       using timevar_start, this contains the start time.  */
      51    struct timevar_time_def start_time;
      52  
      53    /* The name of this timing variable.  */
      54    const char *name;
      55  
      56    /* Non-zero if this timing variable is running as a standalone
      57       timer.  */
      58    unsigned standalone : 1;
      59  
      60    /* Non-zero if this timing variable was ever started or pushed onto
      61       the timing stack.  */
      62    unsigned used : 1;
      63  };
      64  
      65  /* An element on the timing stack.  Elapsed time is attributed to the
      66     topmost timing variable on the stack.  */
      67  
      68  struct timevar_stack_def
      69  {
      70    /* The timing variable at this stack level.  */
      71    struct timevar_def *timevar;
      72  
      73    /* The next lower timing variable context in the stack.  */
      74    struct timevar_stack_def *next;
      75  };
      76  
      77  /* Declared timing variables.  Constructed from the contents of
      78     timevar.def.  */
      79  static struct timevar_def timevars[TIMEVAR_LAST];
      80  
      81  /* The top of the timing stack.  */
      82  static struct timevar_stack_def *stack;
      83  
      84  /* A list of unused (i.e. allocated and subsequently popped)
      85     timevar_stack_def instances.  */
      86  static struct timevar_stack_def *unused_stack_instances;
      87  
      88  /* The time at which the topmost element on the timing stack was
      89     pushed.  Time elapsed since then is attributed to the topmost
      90     element.  */
      91  static struct timevar_time_def start_time;
      92  
      93  /* Fill the current times into TIME.  */
      94  
      95  static void
      96  set_to_current_time (struct timevar_time_def *now)
      97  {
      98    now->user = 0;
      99    now->sys  = 0;
     100    now->wall = 0;
     101  
     102    if (!timevar_enabled)
     103      return;
     104  
     105    struct rusage self;
     106    getrusage (RUSAGE_SELF, &self);
     107    struct rusage chld;
     108    getrusage (RUSAGE_CHILDREN, &chld);
     109  
     110    now->user =
     111      xtime_make (self.ru_utime.tv_sec + chld.ru_utime.tv_sec,
     112                  (self.ru_utime.tv_usec + chld.ru_utime.tv_usec) * 1000);
     113  
     114    now->sys =
     115      xtime_make (self.ru_stime.tv_sec + chld.ru_stime.tv_sec,
     116                  (self.ru_stime.tv_usec + chld.ru_stime.tv_usec) * 1000);
     117  
     118    now->wall = gethrxtime();
     119  }
     120  
     121  /* Return the current time.  */
     122  
     123  static struct timevar_time_def
     124  get_current_time (void)
     125  {
     126    struct timevar_time_def now;
     127    set_to_current_time (&now);
     128    return now;
     129  }
     130  
     131  /* Add the difference between STOP and START to TIMER.  */
     132  
     133  static void
     134  timevar_accumulate (struct timevar_time_def *timer,
     135                      const struct timevar_time_def *start,
     136                      const struct timevar_time_def *stop)
     137  {
     138    timer->user += stop->user - start->user;
     139    timer->sys += stop->sys - start->sys;
     140    timer->wall += stop->wall - start->wall;
     141  }
     142  
     143  void
     144  timevar_init ()
     145  {
     146    if (!timevar_enabled)
     147      return;
     148  
     149    /* Zero all elapsed times.  */
     150    memset ((void *) timevars, 0, sizeof (timevars));
     151  
     152    /* Initialize the names of timing variables.  */
     153  #define DEFTIMEVAR(identifier__, name__) \
     154    timevars[identifier__].name = name__;
     155  #include "timevar.def"
     156  #undef DEFTIMEVAR
     157  }
     158  
     159  void
     160  timevar_push (timevar_id_t timevar)
     161  {
     162    if (!timevar_enabled)
     163      return;
     164  
     165    struct timevar_def *tv = &timevars[timevar];
     166  
     167    /* Mark this timing variable as used.  */
     168    tv->used = 1;
     169  
     170    /* Can't push a standalone timer.  */
     171    if (tv->standalone)
     172      abort ();
     173  
     174    /* What time is it?  */
     175    struct timevar_time_def const now = get_current_time ();
     176  
     177    /* If the stack isn't empty, attribute the current elapsed time to
     178       the old topmost element.  */
     179    if (stack)
     180      timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
     181  
     182    /* Reset the start time; from now on, time is attributed to
     183       TIMEVAR.  */
     184    start_time = now;
     185  
     186    /* See if we have a previously-allocated stack instance.  If so,
     187       take it off the list.  If not, malloc a new one.  */
     188    struct timevar_stack_def *context = NULL;
     189    if (unused_stack_instances != NULL)
     190      {
     191        context = unused_stack_instances;
     192        unused_stack_instances = unused_stack_instances->next;
     193      }
     194    else
     195      context = (struct timevar_stack_def *)
     196        xmalloc (sizeof (struct timevar_stack_def));
     197  
     198    /* Fill it in and put it on the stack.  */
     199    context->timevar = tv;
     200    context->next = stack;
     201    stack = context;
     202  }
     203  
     204  void
     205  timevar_pop (timevar_id_t timevar)
     206  {
     207    if (!timevar_enabled)
     208      return;
     209  
     210    if (&timevars[timevar] != stack->timevar)
     211      abort ();
     212  
     213    /* What time is it?  */
     214    struct timevar_time_def const now = get_current_time ();
     215  
     216    /* Attribute the elapsed time to the element we're popping.  */
     217    struct timevar_stack_def *popped = stack;
     218    timevar_accumulate (&popped->timevar->elapsed, &start_time, &now);
     219  
     220    /* Reset the start time; from now on, time is attributed to the
     221       element just exposed on the stack.  */
     222    start_time = now;
     223  
     224    /* Take the item off the stack.  */
     225    stack = stack->next;
     226  
     227    /* Don't delete the stack element; instead, add it to the list of
     228       unused elements for later use.  */
     229    popped->next = unused_stack_instances;
     230    unused_stack_instances = popped;
     231  }
     232  
     233  void
     234  timevar_start (timevar_id_t timevar)
     235  {
     236    if (!timevar_enabled)
     237      return;
     238  
     239    struct timevar_def *tv = &timevars[timevar];
     240  
     241    /* Mark this timing variable as used.  */
     242    tv->used = 1;
     243  
     244    /* Don't allow the same timing variable to be started more than
     245       once.  */
     246    if (tv->standalone)
     247      abort ();
     248    tv->standalone = 1;
     249  
     250    set_to_current_time (&tv->start_time);
     251  }
     252  
     253  void
     254  timevar_stop (timevar_id_t timevar)
     255  {
     256    if (!timevar_enabled)
     257      return;
     258  
     259    struct timevar_def *tv = &timevars[timevar];
     260  
     261    /* TIMEVAR must have been started via timevar_start.  */
     262    if (!tv->standalone)
     263      abort ();
     264  
     265    struct timevar_time_def const now = get_current_time ();
     266    timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
     267  }
     268  
     269  void
     270  timevar_get (timevar_id_t timevar,
     271               struct timevar_time_def *elapsed)
     272  {
     273    struct timevar_def *tv = &timevars[timevar];
     274    *elapsed = tv->elapsed;
     275  
     276    /* Is TIMEVAR currently running as a standalone timer?  */
     277    if (tv->standalone)
     278      {
     279        struct timevar_time_def const now = get_current_time ();
     280        timevar_accumulate (elapsed, &tv->start_time, &now);
     281      }
     282    /* Or is TIMEVAR at the top of the timer stack?  */
     283    else if (stack->timevar == tv)
     284      {
     285        struct timevar_time_def const now = get_current_time ();
     286        timevar_accumulate (elapsed, &start_time, &now);
     287      }
     288  }
     289  
     290  void
     291  timevar_print (FILE *fp)
     292  {
     293    if (!timevar_enabled)
     294      return;
     295  
     296    /* Update timing information in case we're calling this from GDB.  */
     297  
     298    if (fp == 0)
     299      fp = stderr;
     300  
     301    /* What time is it?  */
     302    struct timevar_time_def const now = get_current_time ();
     303  
     304    /* If the stack isn't empty, attribute the current elapsed time to
     305       the old topmost element.  */
     306    if (stack)
     307      timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
     308  
     309    /* Reset the start time; from now on, time is attributed to
     310       TIMEVAR.  */
     311    start_time = now;
     312  
     313    struct timevar_time_def const* total = &timevars[tv_total].elapsed;
     314  
     315    fprintf (fp, "%-22s\n",
     316             _("Execution times (seconds)"));
     317    fprintf (fp, " %-22s   %-13s %-13s %-16s\n",
     318             "", _("CPU user"), _("CPU system"), _("wall clock"));
     319    for (unsigned /* timevar_id_t */ id = 0; id < (unsigned) TIMEVAR_LAST; ++id)
     320      {
     321        /* Don't print the total execution time here; that goes at the
     322           end.  */
     323        if ((timevar_id_t) id == tv_total)
     324          continue;
     325  
     326        /* Don't print timing variables that were never used.  */
     327        struct timevar_def *tv = &timevars[(timevar_id_t) id];
     328        if (!tv->used)
     329          continue;
     330  
     331        /* Percentages.  */
     332        const int usr = total->user ? tv->elapsed.user * 100 / total->user : 0;
     333        const int sys = total->sys ? tv->elapsed.sys * 100 / total->sys : 0;
     334        const int wall = total->wall ? tv->elapsed.wall * 100 / total->wall : 0;
     335  
     336        /* Ignore insignificant lines.  */
     337        if (!usr && !sys && !wall)
     338          continue;
     339  
     340        fprintf (fp, " %-22s", tv->name);
     341        fprintf (fp, "%8.3f (%2d%%)", tv->elapsed.user * 1e-9, usr);
     342        fprintf (fp, "%8.3f (%2d%%)", tv->elapsed.sys * 1e-9, sys);
     343        fprintf (fp, "%11.6f (%2d%%)\n", tv->elapsed.wall * 1e-9, wall);
     344      }
     345  
     346    /* Print total time.  */
     347    fprintf (fp, " %-22s", timevars[tv_total].name);
     348    fprintf (fp, "%8.3f      ", total->user * 1e-9);
     349    fprintf (fp, "%8.3f      ", total->sys * 1e-9);
     350    fprintf (fp, "%11.6f\n", total->wall * 1e-9);
     351  }