exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / timevar.c
blob02e06dc83834f76d8cc60514416c3f95a5dde4c6
1 /* Timing variables for measuring compiler performance.
3 Copyright (C) 2000, 2002, 2004, 2006, 2009-2015, 2018-2024 Free Software
4 Foundation, Inc.
6 Contributed by Alex Samuel <samuel@codesourcery.com>
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.
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.
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/>. */
21 #include <config.h>
23 /* Specification. */
24 #include "timevar.h"
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>
33 #include "gethrxtime.h"
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36 #include "xalloc.h"
38 /* See timevar.h for an explanation of timing variables. */
40 int timevar_enabled = 0;
42 /* A timing variable. */
44 struct timevar_def
46 /* Elapsed time for this variable. */
47 struct timevar_time_def elapsed;
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;
53 /* The name of this timing variable. */
54 const char *name;
56 /* Non-zero if this timing variable is running as a standalone
57 timer. */
58 unsigned standalone : 1;
60 /* Non-zero if this timing variable was ever started or pushed onto
61 the timing stack. */
62 unsigned used : 1;
65 /* An element on the timing stack. Elapsed time is attributed to the
66 topmost timing variable on the stack. */
68 struct timevar_stack_def
70 /* The timing variable at this stack level. */
71 struct timevar_def *timevar;
73 /* The next lower timing variable context in the stack. */
74 struct timevar_stack_def *next;
77 /* Declared timing variables. Constructed from the contents of
78 timevar.def. */
79 static struct timevar_def timevars[TIMEVAR_LAST];
81 /* The top of the timing stack. */
82 static struct timevar_stack_def *stack;
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;
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;
93 /* Fill the current times into TIME. */
95 static void
96 set_to_current_time (struct timevar_time_def *now)
98 now->user = 0;
99 now->sys = 0;
100 now->wall = 0;
102 if (!timevar_enabled)
103 return;
105 struct rusage self;
106 getrusage (RUSAGE_SELF, &self);
107 struct rusage chld;
108 getrusage (RUSAGE_CHILDREN, &chld);
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);
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);
118 now->wall = gethrxtime();
121 /* Return the current time. */
123 static struct timevar_time_def
124 get_current_time (void)
126 struct timevar_time_def now;
127 set_to_current_time (&now);
128 return now;
131 /* Add the difference between STOP and START to TIMER. */
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)
138 timer->user += stop->user - start->user;
139 timer->sys += stop->sys - start->sys;
140 timer->wall += stop->wall - start->wall;
143 void
144 timevar_init ()
146 if (!timevar_enabled)
147 return;
149 /* Zero all elapsed times. */
150 memset ((void *) timevars, 0, sizeof (timevars));
152 /* Initialize the names of timing variables. */
153 #define DEFTIMEVAR(identifier__, name__) \
154 timevars[identifier__].name = name__;
155 #include "timevar.def"
156 #undef DEFTIMEVAR
159 void
160 timevar_push (timevar_id_t timevar)
162 if (!timevar_enabled)
163 return;
165 struct timevar_def *tv = &timevars[timevar];
167 /* Mark this timing variable as used. */
168 tv->used = 1;
170 /* Can't push a standalone timer. */
171 if (tv->standalone)
172 abort ();
174 /* What time is it? */
175 struct timevar_time_def const now = get_current_time ();
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);
182 /* Reset the start time; from now on, time is attributed to
183 TIMEVAR. */
184 start_time = now;
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)
191 context = unused_stack_instances;
192 unused_stack_instances = unused_stack_instances->next;
194 else
195 context = (struct timevar_stack_def *)
196 xmalloc (sizeof (struct timevar_stack_def));
198 /* Fill it in and put it on the stack. */
199 context->timevar = tv;
200 context->next = stack;
201 stack = context;
204 void
205 timevar_pop (timevar_id_t timevar)
207 if (!timevar_enabled)
208 return;
210 if (&timevars[timevar] != stack->timevar)
211 abort ();
213 /* What time is it? */
214 struct timevar_time_def const now = get_current_time ();
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);
220 /* Reset the start time; from now on, time is attributed to the
221 element just exposed on the stack. */
222 start_time = now;
224 /* Take the item off the stack. */
225 stack = stack->next;
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;
233 void
234 timevar_start (timevar_id_t timevar)
236 if (!timevar_enabled)
237 return;
239 struct timevar_def *tv = &timevars[timevar];
241 /* Mark this timing variable as used. */
242 tv->used = 1;
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;
250 set_to_current_time (&tv->start_time);
253 void
254 timevar_stop (timevar_id_t timevar)
256 if (!timevar_enabled)
257 return;
259 struct timevar_def *tv = &timevars[timevar];
261 /* TIMEVAR must have been started via timevar_start. */
262 if (!tv->standalone)
263 abort ();
265 struct timevar_time_def const now = get_current_time ();
266 timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
269 void
270 timevar_get (timevar_id_t timevar,
271 struct timevar_time_def *elapsed)
273 struct timevar_def *tv = &timevars[timevar];
274 *elapsed = tv->elapsed;
276 /* Is TIMEVAR currently running as a standalone timer? */
277 if (tv->standalone)
279 struct timevar_time_def const now = get_current_time ();
280 timevar_accumulate (elapsed, &tv->start_time, &now);
282 /* Or is TIMEVAR at the top of the timer stack? */
283 else if (stack->timevar == tv)
285 struct timevar_time_def const now = get_current_time ();
286 timevar_accumulate (elapsed, &start_time, &now);
290 void
291 timevar_print (FILE *fp)
293 if (!timevar_enabled)
294 return;
296 /* Update timing information in case we're calling this from GDB. */
298 if (fp == 0)
299 fp = stderr;
301 /* What time is it? */
302 struct timevar_time_def const now = get_current_time ();
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);
309 /* Reset the start time; from now on, time is attributed to
310 TIMEVAR. */
311 start_time = now;
313 struct timevar_time_def const* total = &timevars[tv_total].elapsed;
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)
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;
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;
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;
336 /* Ignore insignificant lines. */
337 if (!usr && !sys && !wall)
338 continue;
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);
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);