1/* Timing variables for measuring compiler performance.
2
3 Copyright (C) 2000, 2002, 2004, 2006, 2009-2015, 2018-2019 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 <http://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
40int timevar_enabled = 0;
41
42/* A timing variable. */
43
44struct 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
68struct 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. */
79static struct timevar_def timevars[TIMEVAR_LAST];
80
81/* The top of the timing stack. */
82static struct timevar_stack_def *stack;
83
84/* A list of unused (i.e. allocated and subsequently popped)
85 timevar_stack_def instances. */
86static 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. */
91static struct timevar_time_def start_time;
92
93/* Fill the current times into TIME. */
94
95static void
96set_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
123static struct timevar_time_def
124get_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
133static void
134timevar_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
143void
144timevar_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
159void
160timevar_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
204void
205timevar_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
233void
234timevar_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
253void
254timevar_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
269void
270timevar_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
290void
291timevar_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}
352