root/maint/gnulib/lib/timevar.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_to_current_time
  2. get_current_time
  3. timevar_accumulate
  4. timevar_init
  5. timevar_push
  6. timevar_pop
  7. timevar_start
  8. timevar_stop
  9. timevar_get
  10. timevar_print

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 ()
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */