11debfc3dSmrg /* Timing variables for measuring compiler performance.
2*8feb0f0bSmrg Copyright (C) 2000-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Alex Samuel <samuel@codesourcery.com>
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg #include "config.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "timevar.h"
251debfc3dSmrg #include "options.h"
261debfc3dSmrg
271debfc3dSmrg #ifndef HAVE_CLOCK_T
281debfc3dSmrg typedef int clock_t;
291debfc3dSmrg #endif
301debfc3dSmrg
311debfc3dSmrg #ifndef HAVE_STRUCT_TMS
321debfc3dSmrg struct tms
331debfc3dSmrg {
341debfc3dSmrg clock_t tms_utime;
351debfc3dSmrg clock_t tms_stime;
361debfc3dSmrg clock_t tms_cutime;
371debfc3dSmrg clock_t tms_cstime;
381debfc3dSmrg };
391debfc3dSmrg #endif
401debfc3dSmrg
411debfc3dSmrg #ifndef RUSAGE_SELF
421debfc3dSmrg # define RUSAGE_SELF 0
431debfc3dSmrg #endif
441debfc3dSmrg
451debfc3dSmrg /* Calculation of scale factor to convert ticks to microseconds.
461debfc3dSmrg We mustn't use CLOCKS_PER_SEC except with clock(). */
471debfc3dSmrg #if HAVE_SYSCONF && defined _SC_CLK_TCK
481debfc3dSmrg # define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
491debfc3dSmrg #else
501debfc3dSmrg # ifdef CLK_TCK
511debfc3dSmrg # define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
521debfc3dSmrg # else
531debfc3dSmrg # ifdef HZ
541debfc3dSmrg # define TICKS_PER_SECOND HZ /* traditional UNIX */
551debfc3dSmrg # else
561debfc3dSmrg # define TICKS_PER_SECOND 100 /* often the correct value */
571debfc3dSmrg # endif
581debfc3dSmrg # endif
591debfc3dSmrg #endif
601debfc3dSmrg
611debfc3dSmrg /* Prefer times to getrusage to clock (each gives successively less
621debfc3dSmrg information). */
631debfc3dSmrg #ifdef HAVE_TIMES
641debfc3dSmrg # if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
651debfc3dSmrg extern clock_t times (struct tms *);
661debfc3dSmrg # endif
671debfc3dSmrg # define USE_TIMES
681debfc3dSmrg # define HAVE_USER_TIME
691debfc3dSmrg # define HAVE_SYS_TIME
701debfc3dSmrg # define HAVE_WALL_TIME
711debfc3dSmrg #else
721debfc3dSmrg #ifdef HAVE_GETRUSAGE
731debfc3dSmrg # if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
741debfc3dSmrg extern int getrusage (int, struct rusage *);
751debfc3dSmrg # endif
761debfc3dSmrg # define USE_GETRUSAGE
771debfc3dSmrg # define HAVE_USER_TIME
781debfc3dSmrg # define HAVE_SYS_TIME
791debfc3dSmrg #else
801debfc3dSmrg #ifdef HAVE_CLOCK
811debfc3dSmrg # if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
821debfc3dSmrg extern clock_t clock (void);
831debfc3dSmrg # endif
841debfc3dSmrg # define USE_CLOCK
851debfc3dSmrg # define HAVE_USER_TIME
861debfc3dSmrg #endif
871debfc3dSmrg #endif
881debfc3dSmrg #endif
891debfc3dSmrg
901debfc3dSmrg /* libc is very likely to have snuck a call to sysconf() into one of
911debfc3dSmrg the underlying constants, and that can be very slow, so we have to
921debfc3dSmrg precompute them. Whose wonderful idea was it to make all those
931debfc3dSmrg _constants_ variable at run time, anyway? */
941debfc3dSmrg #ifdef USE_TIMES
951debfc3dSmrg static double ticks_to_msec;
961debfc3dSmrg #define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND)
971debfc3dSmrg #endif
981debfc3dSmrg
991debfc3dSmrg #ifdef USE_CLOCK
1001debfc3dSmrg static double clocks_to_msec;
1011debfc3dSmrg #define CLOCKS_TO_MSEC (1 / (double)CLOCKS_PER_SEC)
1021debfc3dSmrg #endif
1031debfc3dSmrg
1041debfc3dSmrg /* Non-NULL if timevars should be used. In GCC, this happens with
1051debfc3dSmrg the -ftime-report flag. */
1061debfc3dSmrg
1071debfc3dSmrg timer *g_timer;
1081debfc3dSmrg
1091debfc3dSmrg /* Total amount of memory allocated by garbage collector. */
1101debfc3dSmrg
1111debfc3dSmrg size_t timevar_ggc_mem_total;
1121debfc3dSmrg
1131debfc3dSmrg /* The amount of memory that will cause us to report the timevar even
1141debfc3dSmrg if the time spent is not significant. */
1151debfc3dSmrg
1161debfc3dSmrg #define GGC_MEM_BOUND (1 << 20)
1171debfc3dSmrg
1181debfc3dSmrg /* See timevar.h for an explanation of timing variables. */
1191debfc3dSmrg
1201debfc3dSmrg static void get_time (struct timevar_time_def *);
1211debfc3dSmrg static void timevar_accumulate (struct timevar_time_def *,
1221debfc3dSmrg struct timevar_time_def *,
1231debfc3dSmrg struct timevar_time_def *);
1241debfc3dSmrg
1251debfc3dSmrg /* The implementation of timing events for jit client code, allowing
1261debfc3dSmrg arbitrary named items to appear on the timing stack. */
1271debfc3dSmrg
1281debfc3dSmrg class timer::named_items
1291debfc3dSmrg {
1301debfc3dSmrg public:
1311debfc3dSmrg named_items (timer *t);
1321debfc3dSmrg ~named_items ();
1331debfc3dSmrg
1341debfc3dSmrg void push (const char *item_name);
1351debfc3dSmrg void pop ();
1361debfc3dSmrg void print (FILE *fp, const timevar_time_def *total);
1371debfc3dSmrg
1381debfc3dSmrg private:
1391debfc3dSmrg /* Which timer instance does this relate to? */
1401debfc3dSmrg timer *m_timer;
1411debfc3dSmrg
1421debfc3dSmrg /* Dictionary, mapping from item names to timevar_def.
1431debfc3dSmrg Note that currently we merely store/compare the raw string
1441debfc3dSmrg pointers provided by client code; we don't take a copy,
1451debfc3dSmrg or use strcmp. */
1461debfc3dSmrg hash_map <const char *, timer::timevar_def> m_hash_map;
1471debfc3dSmrg
1481debfc3dSmrg /* The order in which items were originally inserted. */
1491debfc3dSmrg auto_vec <const char *> m_names;
1501debfc3dSmrg };
1511debfc3dSmrg
1521debfc3dSmrg /* The constructor for class timer::named_items. */
1531debfc3dSmrg
named_items(timer * t)1541debfc3dSmrg timer::named_items::named_items (timer *t)
1551debfc3dSmrg : m_timer (t),
1561debfc3dSmrg m_hash_map (),
1571debfc3dSmrg m_names ()
1581debfc3dSmrg {
1591debfc3dSmrg }
1601debfc3dSmrg
1611debfc3dSmrg /* The destructor for class timer::named_items. */
1621debfc3dSmrg
~named_items()1631debfc3dSmrg timer::named_items::~named_items ()
1641debfc3dSmrg {
1651debfc3dSmrg }
1661debfc3dSmrg
1671debfc3dSmrg /* Push the named item onto the timer stack. */
1681debfc3dSmrg
1691debfc3dSmrg void
push(const char * item_name)1701debfc3dSmrg timer::named_items::push (const char *item_name)
1711debfc3dSmrg {
1721debfc3dSmrg gcc_assert (item_name);
1731debfc3dSmrg
1741debfc3dSmrg bool existed;
1751debfc3dSmrg timer::timevar_def *def = &m_hash_map.get_or_insert (item_name, &existed);
1761debfc3dSmrg if (!existed)
1771debfc3dSmrg {
1781debfc3dSmrg def->elapsed.user = 0;
1791debfc3dSmrg def->elapsed.sys = 0;
1801debfc3dSmrg def->elapsed.wall = 0;
1811debfc3dSmrg def->name = item_name;
1821debfc3dSmrg def->standalone = 0;
1831debfc3dSmrg m_names.safe_push (item_name);
1841debfc3dSmrg }
1851debfc3dSmrg m_timer->push_internal (def);
1861debfc3dSmrg }
1871debfc3dSmrg
1881debfc3dSmrg /* Pop the top item from the timer stack. */
1891debfc3dSmrg
1901debfc3dSmrg void
pop()1911debfc3dSmrg timer::named_items::pop ()
1921debfc3dSmrg {
1931debfc3dSmrg m_timer->pop_internal ();
1941debfc3dSmrg }
1951debfc3dSmrg
1961debfc3dSmrg /* Print the given client item. Helper function for timer::print. */
1971debfc3dSmrg
1981debfc3dSmrg void
print(FILE * fp,const timevar_time_def * total)1991debfc3dSmrg timer::named_items::print (FILE *fp, const timevar_time_def *total)
2001debfc3dSmrg {
2011debfc3dSmrg unsigned int i;
2021debfc3dSmrg const char *item_name;
2031debfc3dSmrg fprintf (fp, "Client items:\n");
2041debfc3dSmrg FOR_EACH_VEC_ELT (m_names, i, item_name)
2051debfc3dSmrg {
2061debfc3dSmrg timer::timevar_def *def = m_hash_map.get (item_name);
2071debfc3dSmrg gcc_assert (def);
2081debfc3dSmrg m_timer->print_row (fp, total, def->name, def->elapsed);
2091debfc3dSmrg }
2101debfc3dSmrg }
2111debfc3dSmrg
2121debfc3dSmrg /* Fill the current times into TIME. The definition of this function
2131debfc3dSmrg also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and
2141debfc3dSmrg HAVE_WALL_TIME macros. */
2151debfc3dSmrg
2161debfc3dSmrg static void
get_time(struct timevar_time_def * now)2171debfc3dSmrg get_time (struct timevar_time_def *now)
2181debfc3dSmrg {
2191debfc3dSmrg now->user = 0;
2201debfc3dSmrg now->sys = 0;
2211debfc3dSmrg now->wall = 0;
2221debfc3dSmrg now->ggc_mem = timevar_ggc_mem_total;
2231debfc3dSmrg
2241debfc3dSmrg {
2251debfc3dSmrg #ifdef USE_TIMES
2261debfc3dSmrg struct tms tms;
2271debfc3dSmrg now->wall = times (&tms) * ticks_to_msec;
2281debfc3dSmrg now->user = tms.tms_utime * ticks_to_msec;
2291debfc3dSmrg now->sys = tms.tms_stime * ticks_to_msec;
2301debfc3dSmrg #endif
2311debfc3dSmrg #ifdef USE_GETRUSAGE
2321debfc3dSmrg struct rusage rusage;
2331debfc3dSmrg getrusage (RUSAGE_SELF, &rusage);
2341debfc3dSmrg now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6;
2351debfc3dSmrg now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6;
2361debfc3dSmrg #endif
2371debfc3dSmrg #ifdef USE_CLOCK
2381debfc3dSmrg now->user = clock () * clocks_to_msec;
2391debfc3dSmrg #endif
2401debfc3dSmrg }
2411debfc3dSmrg }
2421debfc3dSmrg
2431debfc3dSmrg /* Add the difference between STOP_TIME and START_TIME to TIMER. */
2441debfc3dSmrg
2451debfc3dSmrg static void
timevar_accumulate(struct timevar_time_def * timer,struct timevar_time_def * start_time,struct timevar_time_def * stop_time)2461debfc3dSmrg timevar_accumulate (struct timevar_time_def *timer,
2471debfc3dSmrg struct timevar_time_def *start_time,
2481debfc3dSmrg struct timevar_time_def *stop_time)
2491debfc3dSmrg {
2501debfc3dSmrg timer->user += stop_time->user - start_time->user;
2511debfc3dSmrg timer->sys += stop_time->sys - start_time->sys;
2521debfc3dSmrg timer->wall += stop_time->wall - start_time->wall;
2531debfc3dSmrg timer->ggc_mem += stop_time->ggc_mem - start_time->ggc_mem;
2541debfc3dSmrg }
2551debfc3dSmrg
2561debfc3dSmrg /* Class timer's constructor. */
2571debfc3dSmrg
timer()2581debfc3dSmrg timer::timer () :
2591debfc3dSmrg m_stack (NULL),
2601debfc3dSmrg m_unused_stack_instances (NULL),
2611debfc3dSmrg m_start_time (),
2621debfc3dSmrg m_jit_client_items (NULL)
2631debfc3dSmrg {
2641debfc3dSmrg /* Zero all elapsed times. */
2651debfc3dSmrg memset (m_timevars, 0, sizeof (m_timevars));
2661debfc3dSmrg
2671debfc3dSmrg /* Initialize the names of timing variables. */
2681debfc3dSmrg #define DEFTIMEVAR(identifier__, name__) \
2691debfc3dSmrg m_timevars[identifier__].name = name__;
2701debfc3dSmrg #include "timevar.def"
2711debfc3dSmrg #undef DEFTIMEVAR
2721debfc3dSmrg
2731debfc3dSmrg /* Initialize configuration-specific state.
2741debfc3dSmrg Ideally this would be one-time initialization. */
2751debfc3dSmrg #ifdef USE_TIMES
2761debfc3dSmrg ticks_to_msec = TICKS_TO_MSEC;
2771debfc3dSmrg #endif
2781debfc3dSmrg #ifdef USE_CLOCK
2791debfc3dSmrg clocks_to_msec = CLOCKS_TO_MSEC;
2801debfc3dSmrg #endif
2811debfc3dSmrg }
2821debfc3dSmrg
2831debfc3dSmrg /* Class timer's destructor. */
2841debfc3dSmrg
~timer()2851debfc3dSmrg timer::~timer ()
2861debfc3dSmrg {
2871debfc3dSmrg timevar_stack_def *iter, *next;
2881debfc3dSmrg
2891debfc3dSmrg for (iter = m_stack; iter; iter = next)
2901debfc3dSmrg {
2911debfc3dSmrg next = iter->next;
2921debfc3dSmrg free (iter);
2931debfc3dSmrg }
2941debfc3dSmrg for (iter = m_unused_stack_instances; iter; iter = next)
2951debfc3dSmrg {
2961debfc3dSmrg next = iter->next;
2971debfc3dSmrg free (iter);
2981debfc3dSmrg }
2991debfc3dSmrg for (unsigned i = 0; i < TIMEVAR_LAST; ++i)
3001debfc3dSmrg delete m_timevars[i].children;
3011debfc3dSmrg
3021debfc3dSmrg delete m_jit_client_items;
3031debfc3dSmrg }
3041debfc3dSmrg
3051debfc3dSmrg /* Initialize timing variables. */
3061debfc3dSmrg
3071debfc3dSmrg void
timevar_init(void)3081debfc3dSmrg timevar_init (void)
3091debfc3dSmrg {
3101debfc3dSmrg if (g_timer)
3111debfc3dSmrg return;
3121debfc3dSmrg
3131debfc3dSmrg g_timer = new timer ();
3141debfc3dSmrg }
3151debfc3dSmrg
3161debfc3dSmrg /* Push TIMEVAR onto the timing stack. No further elapsed time is
3171debfc3dSmrg attributed to the previous topmost timing variable on the stack;
3181debfc3dSmrg subsequent elapsed time is attributed to TIMEVAR, until it is
3191debfc3dSmrg popped or another element is pushed on top.
3201debfc3dSmrg
3211debfc3dSmrg TIMEVAR cannot be running as a standalone timer. */
3221debfc3dSmrg
3231debfc3dSmrg void
push(timevar_id_t timevar)3241debfc3dSmrg timer::push (timevar_id_t timevar)
3251debfc3dSmrg {
3261debfc3dSmrg struct timevar_def *tv = &m_timevars[timevar];
3271debfc3dSmrg push_internal (tv);
3281debfc3dSmrg }
3291debfc3dSmrg
3301debfc3dSmrg /* Push TV onto the timing stack, either one of the builtin ones
3311debfc3dSmrg for a timevar_id_t, or one provided by client code to libgccjit. */
3321debfc3dSmrg
3331debfc3dSmrg void
push_internal(struct timevar_def * tv)3341debfc3dSmrg timer::push_internal (struct timevar_def *tv)
3351debfc3dSmrg {
3361debfc3dSmrg struct timevar_stack_def *context;
3371debfc3dSmrg struct timevar_time_def now;
3381debfc3dSmrg
3391debfc3dSmrg gcc_assert (tv);
3401debfc3dSmrg
3411debfc3dSmrg /* Mark this timing variable as used. */
3421debfc3dSmrg tv->used = 1;
3431debfc3dSmrg
3441debfc3dSmrg /* Can't push a standalone timer. */
3451debfc3dSmrg gcc_assert (!tv->standalone);
3461debfc3dSmrg
3471debfc3dSmrg /* What time is it? */
3481debfc3dSmrg get_time (&now);
3491debfc3dSmrg
3501debfc3dSmrg /* If the stack isn't empty, attribute the current elapsed time to
3511debfc3dSmrg the old topmost element. */
3521debfc3dSmrg if (m_stack)
3531debfc3dSmrg timevar_accumulate (&m_stack->timevar->elapsed, &m_start_time, &now);
3541debfc3dSmrg
3551debfc3dSmrg /* Reset the start time; from now on, time is attributed to
3561debfc3dSmrg TIMEVAR. */
3571debfc3dSmrg m_start_time = now;
3581debfc3dSmrg
3591debfc3dSmrg /* See if we have a previously-allocated stack instance. If so,
3601debfc3dSmrg take it off the list. If not, malloc a new one. */
3611debfc3dSmrg if (m_unused_stack_instances != NULL)
3621debfc3dSmrg {
3631debfc3dSmrg context = m_unused_stack_instances;
3641debfc3dSmrg m_unused_stack_instances = m_unused_stack_instances->next;
3651debfc3dSmrg }
3661debfc3dSmrg else
3671debfc3dSmrg context = XNEW (struct timevar_stack_def);
3681debfc3dSmrg
3691debfc3dSmrg /* Fill it in and put it on the stack. */
3701debfc3dSmrg context->timevar = tv;
3711debfc3dSmrg context->next = m_stack;
3721debfc3dSmrg m_stack = context;
3731debfc3dSmrg }
3741debfc3dSmrg
3751debfc3dSmrg /* Pop the topmost timing variable element off the timing stack. The
3761debfc3dSmrg popped variable must be TIMEVAR. Elapsed time since the that
3771debfc3dSmrg element was pushed on, or since it was last exposed on top of the
3781debfc3dSmrg stack when the element above it was popped off, is credited to that
3791debfc3dSmrg timing variable. */
3801debfc3dSmrg
3811debfc3dSmrg void
pop(timevar_id_t timevar)3821debfc3dSmrg timer::pop (timevar_id_t timevar)
3831debfc3dSmrg {
3841debfc3dSmrg gcc_assert (&m_timevars[timevar] == m_stack->timevar);
3851debfc3dSmrg
3861debfc3dSmrg pop_internal ();
3871debfc3dSmrg }
3881debfc3dSmrg
3891debfc3dSmrg /* Pop the topmost item from the stack, either one of the builtin ones
3901debfc3dSmrg for a timevar_id_t, or one provided by client code to libgccjit. */
3911debfc3dSmrg
3921debfc3dSmrg void
pop_internal()3931debfc3dSmrg timer::pop_internal ()
3941debfc3dSmrg {
3951debfc3dSmrg struct timevar_time_def now;
3961debfc3dSmrg struct timevar_stack_def *popped = m_stack;
3971debfc3dSmrg
3981debfc3dSmrg /* What time is it? */
3991debfc3dSmrg get_time (&now);
4001debfc3dSmrg
4011debfc3dSmrg /* Attribute the elapsed time to the element we're popping. */
4021debfc3dSmrg timevar_accumulate (&popped->timevar->elapsed, &m_start_time, &now);
4031debfc3dSmrg
4041debfc3dSmrg /* Take the item off the stack. */
4051debfc3dSmrg m_stack = m_stack->next;
4061debfc3dSmrg
4071debfc3dSmrg /* Record the elapsed sub-time to the parent as well. */
4081debfc3dSmrg if (m_stack && time_report_details)
4091debfc3dSmrg {
4101debfc3dSmrg if (! m_stack->timevar->children)
4111debfc3dSmrg m_stack->timevar->children = new child_map_t (5);
4121debfc3dSmrg bool existed_p;
4131debfc3dSmrg timevar_time_def &time
4141debfc3dSmrg = m_stack->timevar->children->get_or_insert (popped->timevar, &existed_p);
4151debfc3dSmrg if (! existed_p)
4161debfc3dSmrg memset (&time, 0, sizeof (timevar_time_def));
4171debfc3dSmrg timevar_accumulate (&time, &m_start_time, &now);
4181debfc3dSmrg }
4191debfc3dSmrg
4201debfc3dSmrg /* Reset the start time; from now on, time is attributed to the
4211debfc3dSmrg element just exposed on the stack. */
4221debfc3dSmrg m_start_time = now;
4231debfc3dSmrg
4241debfc3dSmrg /* Don't delete the stack element; instead, add it to the list of
4251debfc3dSmrg unused elements for later use. */
4261debfc3dSmrg popped->next = m_unused_stack_instances;
4271debfc3dSmrg m_unused_stack_instances = popped;
4281debfc3dSmrg }
4291debfc3dSmrg
4301debfc3dSmrg /* Start timing TIMEVAR independently of the timing stack. Elapsed
4311debfc3dSmrg time until timevar_stop is called for the same timing variable is
4321debfc3dSmrg attributed to TIMEVAR. */
4331debfc3dSmrg
4341debfc3dSmrg void
timevar_start(timevar_id_t timevar)4351debfc3dSmrg timevar_start (timevar_id_t timevar)
4361debfc3dSmrg {
4371debfc3dSmrg if (!g_timer)
4381debfc3dSmrg return;
4391debfc3dSmrg
4401debfc3dSmrg g_timer->start (timevar);
4411debfc3dSmrg }
4421debfc3dSmrg
4431debfc3dSmrg /* See timevar_start above. */
4441debfc3dSmrg
4451debfc3dSmrg void
start(timevar_id_t timevar)4461debfc3dSmrg timer::start (timevar_id_t timevar)
4471debfc3dSmrg {
4481debfc3dSmrg struct timevar_def *tv = &m_timevars[timevar];
4491debfc3dSmrg
4501debfc3dSmrg /* Mark this timing variable as used. */
4511debfc3dSmrg tv->used = 1;
4521debfc3dSmrg
4531debfc3dSmrg /* Don't allow the same timing variable to be started more than
4541debfc3dSmrg once. */
4551debfc3dSmrg gcc_assert (!tv->standalone);
4561debfc3dSmrg tv->standalone = 1;
4571debfc3dSmrg
4581debfc3dSmrg get_time (&tv->start_time);
4591debfc3dSmrg }
4601debfc3dSmrg
4611debfc3dSmrg /* Stop timing TIMEVAR. Time elapsed since timevar_start was called
4621debfc3dSmrg is attributed to it. */
4631debfc3dSmrg
4641debfc3dSmrg void
timevar_stop(timevar_id_t timevar)4651debfc3dSmrg timevar_stop (timevar_id_t timevar)
4661debfc3dSmrg {
4671debfc3dSmrg if (!g_timer)
4681debfc3dSmrg return;
4691debfc3dSmrg
4701debfc3dSmrg g_timer->stop (timevar);
4711debfc3dSmrg }
4721debfc3dSmrg
4731debfc3dSmrg /* See timevar_stop above. */
4741debfc3dSmrg
4751debfc3dSmrg void
stop(timevar_id_t timevar)4761debfc3dSmrg timer::stop (timevar_id_t timevar)
4771debfc3dSmrg {
4781debfc3dSmrg struct timevar_def *tv = &m_timevars[timevar];
4791debfc3dSmrg struct timevar_time_def now;
4801debfc3dSmrg
4811debfc3dSmrg /* TIMEVAR must have been started via timevar_start. */
4821debfc3dSmrg gcc_assert (tv->standalone);
4831debfc3dSmrg tv->standalone = 0; /* Enable a restart. */
4841debfc3dSmrg
4851debfc3dSmrg get_time (&now);
4861debfc3dSmrg timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
4871debfc3dSmrg }
4881debfc3dSmrg
4891debfc3dSmrg
4901debfc3dSmrg /* Conditionally start timing TIMEVAR independently of the timing stack.
4911debfc3dSmrg If the timer is already running, leave it running and return true.
4921debfc3dSmrg Otherwise, start the timer and return false.
4931debfc3dSmrg Elapsed time until the corresponding timevar_cond_stop
4941debfc3dSmrg is called for the same timing variable is attributed to TIMEVAR. */
4951debfc3dSmrg
4961debfc3dSmrg bool
timevar_cond_start(timevar_id_t timevar)4971debfc3dSmrg timevar_cond_start (timevar_id_t timevar)
4981debfc3dSmrg {
4991debfc3dSmrg if (!g_timer)
5001debfc3dSmrg return false;
5011debfc3dSmrg
5021debfc3dSmrg return g_timer->cond_start (timevar);
5031debfc3dSmrg }
5041debfc3dSmrg
5051debfc3dSmrg /* See timevar_cond_start above. */
5061debfc3dSmrg
5071debfc3dSmrg bool
cond_start(timevar_id_t timevar)5081debfc3dSmrg timer::cond_start (timevar_id_t timevar)
5091debfc3dSmrg {
5101debfc3dSmrg struct timevar_def *tv = &m_timevars[timevar];
5111debfc3dSmrg
5121debfc3dSmrg /* Mark this timing variable as used. */
5131debfc3dSmrg tv->used = 1;
5141debfc3dSmrg
5151debfc3dSmrg if (tv->standalone)
5161debfc3dSmrg return true; /* The timevar is already running. */
5171debfc3dSmrg
5181debfc3dSmrg /* Don't allow the same timing variable
5191debfc3dSmrg to be unconditionally started more than once. */
5201debfc3dSmrg tv->standalone = 1;
5211debfc3dSmrg
5221debfc3dSmrg get_time (&tv->start_time);
5231debfc3dSmrg return false; /* The timevar was not already running. */
5241debfc3dSmrg }
5251debfc3dSmrg
5261debfc3dSmrg /* Conditionally stop timing TIMEVAR. The RUNNING parameter must come
5271debfc3dSmrg from the return value of a dynamically matching timevar_cond_start.
5281debfc3dSmrg If the timer had already been RUNNING, do nothing. Otherwise, time
5291debfc3dSmrg elapsed since timevar_cond_start was called is attributed to it. */
5301debfc3dSmrg
5311debfc3dSmrg void
timevar_cond_stop(timevar_id_t timevar,bool running)5321debfc3dSmrg timevar_cond_stop (timevar_id_t timevar, bool running)
5331debfc3dSmrg {
5341debfc3dSmrg if (!g_timer || running)
5351debfc3dSmrg return;
5361debfc3dSmrg
5371debfc3dSmrg g_timer->cond_stop (timevar);
5381debfc3dSmrg }
5391debfc3dSmrg
5401debfc3dSmrg /* See timevar_cond_stop above. */
5411debfc3dSmrg
5421debfc3dSmrg void
cond_stop(timevar_id_t timevar)5431debfc3dSmrg timer::cond_stop (timevar_id_t timevar)
5441debfc3dSmrg {
5451debfc3dSmrg struct timevar_def *tv;
5461debfc3dSmrg struct timevar_time_def now;
5471debfc3dSmrg
5481debfc3dSmrg tv = &m_timevars[timevar];
5491debfc3dSmrg
5501debfc3dSmrg /* TIMEVAR must have been started via timevar_cond_start. */
5511debfc3dSmrg gcc_assert (tv->standalone);
5521debfc3dSmrg tv->standalone = 0; /* Enable a restart. */
5531debfc3dSmrg
5541debfc3dSmrg get_time (&now);
5551debfc3dSmrg timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
5561debfc3dSmrg }
5571debfc3dSmrg
5581debfc3dSmrg /* Push the named item onto the timing stack. */
5591debfc3dSmrg
5601debfc3dSmrg void
push_client_item(const char * item_name)5611debfc3dSmrg timer::push_client_item (const char *item_name)
5621debfc3dSmrg {
5631debfc3dSmrg gcc_assert (item_name);
5641debfc3dSmrg
5651debfc3dSmrg /* Lazily create the named_items instance. */
5661debfc3dSmrg if (!m_jit_client_items)
5671debfc3dSmrg m_jit_client_items = new named_items (this);
5681debfc3dSmrg
5691debfc3dSmrg m_jit_client_items->push (item_name);
5701debfc3dSmrg }
5711debfc3dSmrg
5721debfc3dSmrg /* Pop the top-most client item from the timing stack. */
5731debfc3dSmrg
5741debfc3dSmrg void
pop_client_item()5751debfc3dSmrg timer::pop_client_item ()
5761debfc3dSmrg {
5771debfc3dSmrg gcc_assert (m_jit_client_items);
5781debfc3dSmrg m_jit_client_items->pop ();
5791debfc3dSmrg }
5801debfc3dSmrg
5811debfc3dSmrg /* Validate that phase times are consistent. */
5821debfc3dSmrg
5831debfc3dSmrg void
validate_phases(FILE * fp)5841debfc3dSmrg timer::validate_phases (FILE *fp) const
5851debfc3dSmrg {
5861debfc3dSmrg unsigned int /* timevar_id_t */ id;
5871debfc3dSmrg const timevar_time_def *total = &m_timevars[TV_TOTAL].elapsed;
5881debfc3dSmrg double phase_user = 0.0;
5891debfc3dSmrg double phase_sys = 0.0;
5901debfc3dSmrg double phase_wall = 0.0;
5911debfc3dSmrg size_t phase_ggc_mem = 0;
5921debfc3dSmrg static char phase_prefix[] = "phase ";
5931debfc3dSmrg const double tolerance = 1.000001; /* One part in a million. */
5941debfc3dSmrg
5951debfc3dSmrg for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
5961debfc3dSmrg {
5971debfc3dSmrg const timevar_def *tv = &m_timevars[(timevar_id_t) id];
5981debfc3dSmrg
5991debfc3dSmrg /* Don't evaluate timing variables that were never used. */
6001debfc3dSmrg if (!tv->used)
6011debfc3dSmrg continue;
6021debfc3dSmrg
6031debfc3dSmrg if (strncmp (tv->name, phase_prefix, sizeof phase_prefix - 1) == 0)
6041debfc3dSmrg {
6051debfc3dSmrg phase_user += tv->elapsed.user;
6061debfc3dSmrg phase_sys += tv->elapsed.sys;
6071debfc3dSmrg phase_wall += tv->elapsed.wall;
6081debfc3dSmrg phase_ggc_mem += tv->elapsed.ggc_mem;
6091debfc3dSmrg }
6101debfc3dSmrg }
6111debfc3dSmrg
6121debfc3dSmrg if (phase_user > total->user * tolerance
6131debfc3dSmrg || phase_sys > total->sys * tolerance
6141debfc3dSmrg || phase_wall > total->wall * tolerance
6151debfc3dSmrg || phase_ggc_mem > total->ggc_mem * tolerance)
6161debfc3dSmrg {
6171debfc3dSmrg
6181debfc3dSmrg fprintf (fp, "Timing error: total of phase timers exceeds total time.\n");
6191debfc3dSmrg if (phase_user > total->user)
6201debfc3dSmrg fprintf (fp, "user %24.18e > %24.18e\n", phase_user, total->user);
6211debfc3dSmrg if (phase_sys > total->sys)
6221debfc3dSmrg fprintf (fp, "sys %24.18e > %24.18e\n", phase_sys, total->sys);
6231debfc3dSmrg if (phase_wall > total->wall)
6241debfc3dSmrg fprintf (fp, "wall %24.18e > %24.18e\n", phase_wall, total->wall);
6251debfc3dSmrg if (phase_ggc_mem > total->ggc_mem)
6261debfc3dSmrg fprintf (fp, "ggc_mem %24lu > %24lu\n", (unsigned long)phase_ggc_mem,
6271debfc3dSmrg (unsigned long)total->ggc_mem);
6281debfc3dSmrg gcc_unreachable ();
6291debfc3dSmrg }
6301debfc3dSmrg }
6311debfc3dSmrg
6321debfc3dSmrg /* Helper function for timer::print. */
6331debfc3dSmrg
6341debfc3dSmrg void
print_row(FILE * fp,const timevar_time_def * total,const char * name,const timevar_time_def & elapsed)6351debfc3dSmrg timer::print_row (FILE *fp,
6361debfc3dSmrg const timevar_time_def *total,
6371debfc3dSmrg const char *name, const timevar_time_def &elapsed)
6381debfc3dSmrg {
6391debfc3dSmrg /* The timing variable name. */
640a2dc1f3fSmrg fprintf (fp, " %-35s:", name);
6411debfc3dSmrg
6421debfc3dSmrg #ifdef HAVE_USER_TIME
6431debfc3dSmrg /* Print user-mode time for this process. */
644a2dc1f3fSmrg fprintf (fp, "%7.2f (%3.0f%%)",
6451debfc3dSmrg elapsed.user,
6461debfc3dSmrg (total->user == 0 ? 0 : elapsed.user / total->user) * 100);
6471debfc3dSmrg #endif /* HAVE_USER_TIME */
6481debfc3dSmrg
6491debfc3dSmrg #ifdef HAVE_SYS_TIME
6501debfc3dSmrg /* Print system-mode time for this process. */
651a2dc1f3fSmrg fprintf (fp, "%7.2f (%3.0f%%)",
6521debfc3dSmrg elapsed.sys,
6531debfc3dSmrg (total->sys == 0 ? 0 : elapsed.sys / total->sys) * 100);
6541debfc3dSmrg #endif /* HAVE_SYS_TIME */
6551debfc3dSmrg
6561debfc3dSmrg #ifdef HAVE_WALL_TIME
6571debfc3dSmrg /* Print wall clock time elapsed. */
658a2dc1f3fSmrg fprintf (fp, "%7.2f (%3.0f%%)",
6591debfc3dSmrg elapsed.wall,
6601debfc3dSmrg (total->wall == 0 ? 0 : elapsed.wall / total->wall) * 100);
6611debfc3dSmrg #endif /* HAVE_WALL_TIME */
6621debfc3dSmrg
6631debfc3dSmrg /* Print the amount of ggc memory allocated. */
664a2dc1f3fSmrg fprintf (fp, "%8u kB (%3.0f%%)",
6651debfc3dSmrg (unsigned) (elapsed.ggc_mem >> 10),
6661debfc3dSmrg (total->ggc_mem == 0
6671debfc3dSmrg ? 0
6681debfc3dSmrg : (float) elapsed.ggc_mem / total->ggc_mem) * 100);
6691debfc3dSmrg
6701debfc3dSmrg putc ('\n', fp);
6711debfc3dSmrg }
6721debfc3dSmrg
6731debfc3dSmrg /* Return whether ELAPSED is all zero. */
6741debfc3dSmrg
6751debfc3dSmrg bool
all_zero(const timevar_time_def & elapsed)6761debfc3dSmrg timer::all_zero (const timevar_time_def &elapsed)
6771debfc3dSmrg {
6781debfc3dSmrg const double tiny = 5e-3;
6791debfc3dSmrg return (elapsed.user < tiny
6801debfc3dSmrg && elapsed.sys < tiny
6811debfc3dSmrg && elapsed.wall < tiny
6821debfc3dSmrg && elapsed.ggc_mem < GGC_MEM_BOUND);
6831debfc3dSmrg }
6841debfc3dSmrg
6851debfc3dSmrg /* Summarize timing variables to FP. The timing variable TV_TOTAL has
6861debfc3dSmrg a special meaning -- it's considered to be the total elapsed time,
6871debfc3dSmrg for normalizing the others, and is displayed last. */
6881debfc3dSmrg
6891debfc3dSmrg void
print(FILE * fp)6901debfc3dSmrg timer::print (FILE *fp)
6911debfc3dSmrg {
6921debfc3dSmrg /* Only print stuff if we have some sort of time information. */
6931debfc3dSmrg #if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME)
6941debfc3dSmrg unsigned int /* timevar_id_t */ id;
6951debfc3dSmrg const timevar_time_def *total = &m_timevars[TV_TOTAL].elapsed;
6961debfc3dSmrg struct timevar_time_def now;
6971debfc3dSmrg
6981debfc3dSmrg /* Update timing information in case we're calling this from GDB. */
6991debfc3dSmrg
7001debfc3dSmrg if (fp == 0)
7011debfc3dSmrg fp = stderr;
7021debfc3dSmrg
7031debfc3dSmrg /* What time is it? */
7041debfc3dSmrg get_time (&now);
7051debfc3dSmrg
7061debfc3dSmrg /* If the stack isn't empty, attribute the current elapsed time to
7071debfc3dSmrg the old topmost element. */
7081debfc3dSmrg if (m_stack)
7091debfc3dSmrg timevar_accumulate (&m_stack->timevar->elapsed, &m_start_time, &now);
7101debfc3dSmrg
7111debfc3dSmrg /* Reset the start time; from now on, time is attributed to
7121debfc3dSmrg TIMEVAR. */
7131debfc3dSmrg m_start_time = now;
7141debfc3dSmrg
715a2dc1f3fSmrg fprintf (fp, "\n%-35s%16s%14s%14s%18s\n", "Time variable", "usr", "sys",
716a2dc1f3fSmrg "wall", "GGC");
7171debfc3dSmrg if (m_jit_client_items)
7181debfc3dSmrg fputs ("GCC items:\n", fp);
7191debfc3dSmrg for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
7201debfc3dSmrg {
7211debfc3dSmrg const timevar_def *tv = &m_timevars[(timevar_id_t) id];
7221debfc3dSmrg
7231debfc3dSmrg /* Don't print the total execution time here; that goes at the
7241debfc3dSmrg end. */
7251debfc3dSmrg if ((timevar_id_t) id == TV_TOTAL)
7261debfc3dSmrg continue;
7271debfc3dSmrg
7281debfc3dSmrg /* Don't print timing variables that were never used. */
7291debfc3dSmrg if (!tv->used)
7301debfc3dSmrg continue;
7311debfc3dSmrg
7321debfc3dSmrg bool any_children_with_time = false;
7331debfc3dSmrg if (tv->children)
7341debfc3dSmrg for (child_map_t::iterator i = tv->children->begin ();
7351debfc3dSmrg i != tv->children->end (); ++i)
7361debfc3dSmrg if (! all_zero ((*i).second))
7371debfc3dSmrg {
7381debfc3dSmrg any_children_with_time = true;
7391debfc3dSmrg break;
7401debfc3dSmrg }
7411debfc3dSmrg
7421debfc3dSmrg /* Don't print timing variables if we're going to get a row of
7431debfc3dSmrg zeroes. Unless there are children with non-zero time. */
7441debfc3dSmrg if (! any_children_with_time
7451debfc3dSmrg && all_zero (tv->elapsed))
7461debfc3dSmrg continue;
7471debfc3dSmrg
7481debfc3dSmrg print_row (fp, total, tv->name, tv->elapsed);
7491debfc3dSmrg
7501debfc3dSmrg if (tv->children)
7511debfc3dSmrg for (child_map_t::iterator i = tv->children->begin ();
7521debfc3dSmrg i != tv->children->end (); ++i)
7531debfc3dSmrg {
7541debfc3dSmrg timevar_def *tv2 = (*i).first;
7551debfc3dSmrg /* Don't print timing variables if we're going to get a row of
7561debfc3dSmrg zeroes. */
7571debfc3dSmrg if (! all_zero ((*i).second))
7581debfc3dSmrg {
7591debfc3dSmrg char lname[256];
7601debfc3dSmrg snprintf (lname, 256, "`- %s", tv2->name);
7611debfc3dSmrg print_row (fp, total, lname, (*i).second);
7621debfc3dSmrg }
7631debfc3dSmrg }
7641debfc3dSmrg }
7651debfc3dSmrg if (m_jit_client_items)
7661debfc3dSmrg m_jit_client_items->print (fp, total);
7671debfc3dSmrg
7681debfc3dSmrg /* Print total time. */
769a2dc1f3fSmrg fprintf (fp, " %-35s:", "TOTAL");
7701debfc3dSmrg #ifdef HAVE_USER_TIME
7711debfc3dSmrg fprintf (fp, "%7.2f ", total->user);
7721debfc3dSmrg #endif
7731debfc3dSmrg #ifdef HAVE_SYS_TIME
774a2dc1f3fSmrg fprintf (fp, "%8.2f ", total->sys);
7751debfc3dSmrg #endif
7761debfc3dSmrg #ifdef HAVE_WALL_TIME
777a2dc1f3fSmrg fprintf (fp, "%8.2f ", total->wall);
7781debfc3dSmrg #endif
779a2dc1f3fSmrg fprintf (fp, "%9u kB\n", (unsigned) (total->ggc_mem >> 10));
7801debfc3dSmrg
7811debfc3dSmrg if (CHECKING_P || flag_checking)
7821debfc3dSmrg fprintf (fp, "Extra diagnostic checks enabled; compiler may run slowly.\n");
7831debfc3dSmrg if (CHECKING_P)
7841debfc3dSmrg fprintf (fp, "Configure with --enable-checking=release to disable checks.\n");
7851debfc3dSmrg #ifndef ENABLE_ASSERT_CHECKING
7861debfc3dSmrg fprintf (fp, "Internal checks disabled; compiler is not suited for release.\n");
7871debfc3dSmrg fprintf (fp, "Configure with --enable-checking=release to enable checks.\n");
7881debfc3dSmrg #endif
7891debfc3dSmrg
7901debfc3dSmrg #endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME)
7911debfc3dSmrg || defined (HAVE_WALL_TIME) */
7921debfc3dSmrg
7931debfc3dSmrg validate_phases (fp);
7941debfc3dSmrg }
7951debfc3dSmrg
7961debfc3dSmrg /* Get the name of the topmost item. For use by jit for validating
7971debfc3dSmrg inputs to gcc_jit_timer_pop. */
7981debfc3dSmrg const char *
get_topmost_item_name()7991debfc3dSmrg timer::get_topmost_item_name () const
8001debfc3dSmrg {
8011debfc3dSmrg if (m_stack)
8021debfc3dSmrg return m_stack->timevar->name;
8031debfc3dSmrg else
8041debfc3dSmrg return NULL;
8051debfc3dSmrg }
8061debfc3dSmrg
8071debfc3dSmrg /* Prints a message to stderr stating that time elapsed in STR is
8081debfc3dSmrg TOTAL (given in microseconds). */
8091debfc3dSmrg
8101debfc3dSmrg void
print_time(const char * str,long total)8111debfc3dSmrg print_time (const char *str, long total)
8121debfc3dSmrg {
8131debfc3dSmrg long all_time = get_run_time ();
8141debfc3dSmrg fprintf (stderr,
8151debfc3dSmrg "time in %s: %ld.%06ld (%ld%%)\n",
8161debfc3dSmrg str, total / 1000000, total % 1000000,
8171debfc3dSmrg all_time == 0 ? 0
8181debfc3dSmrg : (long) (((100.0 * (double) total) / (double) all_time) + .5));
8191debfc3dSmrg }
820