1 /* Timing variables for measuring compiler performance.
3 Copyright (C) 2000, 2002, 2004, 2006, 2009-2015, 2018-2020 Free Software
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/>. */
29 #include <sys/resource.h>
31 #include <sys/times.h>
33 #include "gethrxtime.h"
35 #define _(msgid) gettext (msgid)
38 /* See timevar.h for an explanation of timing variables. */
40 int timevar_enabled
= 0;
42 /* A timing variable. */
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. */
56 /* Non-zero if this timing variable is running as a standalone
58 unsigned standalone
: 1;
60 /* Non-zero if this timing variable was ever started or pushed onto
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
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
91 static struct timevar_time_def start_time
;
93 /* Fill the current times into TIME. */
96 set_to_current_time (struct timevar_time_def
*now
)
102 if (!timevar_enabled
)
106 getrusage (RUSAGE_SELF
, &self
);
108 getrusage (RUSAGE_CHILDREN
, &chld
);
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);
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
);
131 /* Add the difference between STOP and START to TIMER. */
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
;
146 if (!timevar_enabled
)
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"
160 timevar_push (timevar_id_t timevar
)
162 if (!timevar_enabled
)
165 struct timevar_def
*tv
= &timevars
[timevar
];
167 /* Mark this timing variable as used. */
170 /* Can't push a standalone timer. */
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. */
180 timevar_accumulate (&stack
->timevar
->elapsed
, &start_time
, &now
);
182 /* Reset the start time; from now on, time is attributed to
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
;
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
;
205 timevar_pop (timevar_id_t timevar
)
207 if (!timevar_enabled
)
210 if (&timevars
[timevar
] != stack
->timevar
)
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. */
224 /* Take the item off the stack. */
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
;
234 timevar_start (timevar_id_t timevar
)
236 if (!timevar_enabled
)
239 struct timevar_def
*tv
= &timevars
[timevar
];
241 /* Mark this timing variable as used. */
244 /* Don't allow the same timing variable to be started more than
250 set_to_current_time (&tv
->start_time
);
254 timevar_stop (timevar_id_t timevar
)
256 if (!timevar_enabled
)
259 struct timevar_def
*tv
= &timevars
[timevar
];
261 /* TIMEVAR must have been started via timevar_start. */
265 struct timevar_time_def
const now
= get_current_time ();
266 timevar_accumulate (&tv
->elapsed
, &tv
->start_time
, &now
);
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? */
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
);
291 timevar_print (FILE *fp
)
293 if (!timevar_enabled
)
296 /* Update timing information in case we're calling this from GDB. */
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. */
307 timevar_accumulate (&stack
->timevar
->elapsed
, &start_time
, &now
);
309 /* Reset the start time; from now on, time is attributed to
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
323 if ((timevar_id_t
) id
== tv_total
)
326 /* Don't print timing variables that were never used. */
327 struct timevar_def
*tv
= &timevars
[(timevar_id_t
) id
];
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
)
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);