#include "config.h"
#include "system.h"
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#include "coretypes.h"
#include "tm.h"
#include "intl.h"
#include "rtl.h"
#include "toplev.h"
#ifndef HAVE_CLOCK_T
typedef int clock_t;
#endif
#ifndef HAVE_STRUCT_TMS
struct tms
{
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
#endif
#ifndef RUSAGE_SELF
# define RUSAGE_SELF 0
#endif
#if HAVE_SYSCONF && defined _SC_CLK_TCK
# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK)
#else
# ifdef CLK_TCK
# define TICKS_PER_SECOND CLK_TCK
# else
# ifdef HZ
# define TICKS_PER_SECOND HZ
# else
# define TICKS_PER_SECOND 100
# endif
# endif
#endif
#ifdef HAVE_TIMES
# if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
extern clock_t times (struct tms *);
# endif
# define USE_TIMES
# define HAVE_USER_TIME
# define HAVE_SYS_TIME
# define HAVE_WALL_TIME
#else
#ifdef HAVE_GETRUSAGE
# if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
extern int getrusage (int, struct rusage *);
# endif
# define USE_GETRUSAGE
# define HAVE_USER_TIME
# define HAVE_SYS_TIME
#else
#ifdef HAVE_CLOCK
# if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
extern clock_t clock (void);
# endif
# define USE_CLOCK
# define HAVE_USER_TIME
#endif
#endif
#endif
#ifdef USE_TIMES
static double ticks_to_msec;
#define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND)
#endif
#ifdef USE_CLOCK
static double clocks_to_msec;
#define CLOCKS_TO_MSEC (1 / (double)CLOCKS_PER_SEC)
#endif
#include "flags.h"
#include "timevar.h"
bool timevar_enable;
size_t timevar_ggc_mem_total;
#define GGC_MEM_BOUND (1 << 20)
struct timevar_def
{
struct timevar_time_def elapsed;
struct timevar_time_def start_time;
const char *name;
unsigned standalone : 1;
unsigned used : 1;
};
struct timevar_stack_def
{
struct timevar_def *timevar;
struct timevar_stack_def *next;
};
static struct timevar_def timevars[TIMEVAR_LAST];
static struct timevar_stack_def *stack;
static struct timevar_stack_def *unused_stack_instances;
static struct timevar_time_def start_time;
static void get_time (struct timevar_time_def *);
static void timevar_accumulate (struct timevar_time_def *,
struct timevar_time_def *,
struct timevar_time_def *);
static void
get_time (struct timevar_time_def *now)
{
now->user = 0;
now->sys = 0;
now->wall = 0;
now->ggc_mem = timevar_ggc_mem_total;
if (!timevar_enable)
return;
{
#ifdef USE_TIMES
struct tms tms;
now->wall = times (&tms) * ticks_to_msec;
now->user = tms.tms_utime * ticks_to_msec;
now->sys = tms.tms_stime * ticks_to_msec;
#endif
#ifdef USE_GETRUSAGE
struct rusage rusage;
getrusage (RUSAGE_SELF, &rusage);
now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6;
now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6;
#endif
#ifdef USE_CLOCK
now->user = clock () * clocks_to_msec;
#endif
}
}
static void
timevar_accumulate (struct timevar_time_def *timer,
struct timevar_time_def *start_time,
struct timevar_time_def *stop_time)
{
timer->user += stop_time->user - start_time->user;
timer->sys += stop_time->sys - start_time->sys;
timer->wall += stop_time->wall - start_time->wall;
timer->ggc_mem += stop_time->ggc_mem - start_time->ggc_mem;
}
void
timevar_init (void)
{
timevar_enable = true;
memset (timevars, 0, sizeof (timevars));
#define DEFTIMEVAR(identifier__, name__) \
timevars[identifier__].name = name__;
#include "timevar.def"
#undef DEFTIMEVAR
#ifdef USE_TIMES
ticks_to_msec = TICKS_TO_MSEC;
#endif
#ifdef USE_CLOCK
clocks_to_msec = CLOCKS_TO_MSEC;
#endif
}
void
timevar_push_1 (timevar_id_t timevar)
{
struct timevar_def *tv = &timevars[timevar];
struct timevar_stack_def *context;
struct timevar_time_def now;
tv->used = 1;
gcc_assert (!tv->standalone);
get_time (&now);
if (stack)
timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
start_time = now;
if (unused_stack_instances != NULL)
{
context = unused_stack_instances;
unused_stack_instances = unused_stack_instances->next;
}
else
context = XNEW (struct timevar_stack_def);
context->timevar = tv;
context->next = stack;
stack = context;
}
void
timevar_pop_1 (timevar_id_t timevar)
{
struct timevar_time_def now;
struct timevar_stack_def *popped = stack;
gcc_assert (&timevars[timevar] == stack->timevar);
get_time (&now);
timevar_accumulate (&popped->timevar->elapsed, &start_time, &now);
start_time = now;
stack = stack->next;
popped->next = unused_stack_instances;
unused_stack_instances = popped;
}
void
timevar_start (timevar_id_t timevar)
{
struct timevar_def *tv = &timevars[timevar];
if (!timevar_enable)
return;
tv->used = 1;
gcc_assert (!tv->standalone);
tv->standalone = 1;
get_time (&tv->start_time);
}
void
timevar_stop (timevar_id_t timevar)
{
struct timevar_def *tv = &timevars[timevar];
struct timevar_time_def now;
if (!timevar_enable)
return;
gcc_assert (tv->standalone);
get_time (&now);
timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
}
void
timevar_print (FILE *fp)
{
#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME)
unsigned int id;
struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed;
struct timevar_time_def now;
if (!timevar_enable)
return;
if (fp == 0)
fp = stderr;
get_time (&now);
if (stack)
timevar_accumulate (&stack->timevar->elapsed, &start_time, &now);
start_time = now;
fputs (_("\nExecution times (seconds)\n"), fp);
for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
{
struct timevar_def *tv = &timevars[(timevar_id_t) id];
const double tiny = 5e-3;
if ((timevar_id_t) id == TV_TOTAL)
continue;
if (!tv->used)
continue;
if (tv->elapsed.user < tiny
&& tv->elapsed.sys < tiny
&& tv->elapsed.wall < tiny
&& tv->elapsed.ggc_mem < GGC_MEM_BOUND)
continue;
fprintf (fp, " %-22s:", tv->name);
#ifdef HAVE_USER_TIME
fprintf (fp, "%7.2f (%2.0f%%) usr",
tv->elapsed.user,
(total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100);
#endif
#ifdef HAVE_SYS_TIME
fprintf (fp, "%7.2f (%2.0f%%) sys",
tv->elapsed.sys,
(total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100);
#endif
#ifdef HAVE_WALL_TIME
fprintf (fp, "%7.2f (%2.0f%%) wall",
tv->elapsed.wall,
(total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100);
#endif
fprintf (fp, "%8u kB (%2.0f%%) ggc",
(unsigned) (tv->elapsed.ggc_mem >> 10),
(total->ggc_mem == 0
? 0
: (float) tv->elapsed.ggc_mem / total->ggc_mem) * 100);
putc ('\n', fp);
}
fputs (_(" TOTAL :"), fp);
#ifdef HAVE_USER_TIME
fprintf (fp, "%7.2f ", total->user);
#endif
#ifdef HAVE_SYS_TIME
fprintf (fp, "%7.2f ", total->sys);
#endif
#ifdef HAVE_WALL_TIME
fprintf (fp, "%7.2f ", total->wall);
#endif
fprintf (fp, "%8u kB\n", (unsigned) (total->ggc_mem >> 10));
#ifdef ENABLE_CHECKING
fprintf (fp, "Extra diagnostic checks enabled; compiler may run slowly.\n");
fprintf (fp, "Configure with --disable-checking to disable checks.\n");
#endif
#endif
}
void
print_time (const char *str, long total)
{
long all_time = get_run_time ();
fprintf (stderr,
_("time in %s: %ld.%06ld (%ld%%)\n"),
str, total / 1000000, total % 1000000,
all_time == 0 ? 0
: (long) (((100.0 * (double) total) / (double) all_time) + .5));
}