#include "config.h"
#include "system.h"
#include "intl.h"
#include "rtl.h"
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_MACH_MACH_TIME_H
#include <mach/mach_time.h>
#define HAVE_MACH_TIME 1
static double timeBaseRatio;
static struct mach_timebase_info tbase;
#else
#define HAVE_MACH_TIME 0
#endif
#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
#if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE
extern int getrusage PARAMS ((int, struct rusage *));
#endif
#if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES
extern clock_t times PARAMS ((struct tms *));
#endif
#if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK
extern clock_t clock PARAMS ((void));
#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
#if defined(__APPLE__) && defined(__POWERPC__) && HAVE_MACH_TIME
#if __POWERPC__
# include <ppc_intrinsics.h>
# define HAVE_WALL_TIME
# define USE_PPC_INTRINSICS
inline double ppc_intrinsic_time()
{
unsigned long hi, lo;
do
{
hi = __mftbu();
lo = __mftb();
} while (hi != __mftbu());
return (hi * 0x100000000ull + lo) * timeBaseRatio;
}
#endif
#elif HAVE_MACH_TIME
# define USE_GETRUSAGE
# define USE_MACH_TIME
# define HAVE_USER_TIME
# define HAVE_SYS_TIME
# define HAVE_WALL_TIME
# else
#ifdef HAVE_TIMES
# define USE_TIMES
# define HAVE_USER_TIME
# define HAVE_SYS_TIME
# define HAVE_WALL_TIME
#else
#ifdef HAVE_GETRUSAGE
# define USE_GETRUSAGE
# define HAVE_USER_TIME
# define HAVE_SYS_TIME
#else
#ifdef HAVE_CLOCK
# define USE_CLOCK
# define HAVE_USER_TIME
#endif
#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"
#include "toplev.h"
#define TIMEVAR_ENABLE (time_report)
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
PARAMS ((struct timevar_time_def *));
static void timevar_accumulate
PARAMS ((struct timevar_time_def *, struct timevar_time_def *,
struct timevar_time_def *));
static void
get_time (now)
struct timevar_time_def *now;
{
now->user = 0;
now->sys = 0;
now->wall = 0;
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
#ifdef USE_MACH_TIME
now->wall = mach_absolute_time() * timeBaseRatio;
#endif
#ifdef USE_PPC_INTRINSICS
now->wall = ppc_intrinsic_time();
#endif
}
}
static void
timevar_accumulate (timer, start_time, stop_time)
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;
}
void
init_timevar ()
{
if (!TIMEVAR_ENABLE)
return;
memset ((void *) 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
#if defined(USE_MACH_TIME) || defined(USE_PPC_INTRINSICS)
mach_timebase_info(&tbase);
timeBaseRatio = ((double) tbase.numer / (double) tbase.denom) * 1e-9;
#endif
}
void
timevar_push (timevar)
timevar_id_t timevar;
{
struct timevar_def *tv = &timevars[timevar];
struct timevar_stack_def *context;
struct timevar_time_def now;
if (!TIMEVAR_ENABLE)
return;
tv->used = 1;
if (tv->standalone)
abort ();
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 = (struct timevar_stack_def *)
xmalloc (sizeof (struct timevar_stack_def));
context->timevar = tv;
context->next = stack;
stack = context;
}
void
timevar_pop (timevar)
timevar_id_t timevar;
{
struct timevar_time_def now;
struct timevar_stack_def *popped = stack;
if (!TIMEVAR_ENABLE)
return;
if (&timevars[timevar] != stack->timevar)
{
sorry ("cannot timevar_pop '%s' when top of timevars stack is '%s'",
timevars[timevar].name, stack->timevar->name);
abort ();
}
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)
timevar_id_t timevar;
{
struct timevar_def *tv = &timevars[timevar];
if (!TIMEVAR_ENABLE)
return;
tv->used = 1;
if (tv->standalone)
abort ();
tv->standalone = 1;
get_time (&tv->start_time);
}
void
timevar_stop (timevar)
timevar_id_t timevar;
{
struct timevar_def *tv = &timevars[timevar];
struct timevar_time_def now;
if (!TIMEVAR_ENABLE)
return;
if (!tv->standalone)
abort ();
get_time (&now);
timevar_accumulate (&tv->elapsed, &tv->start_time, &now);
}
void
timevar_get (timevar, elapsed)
timevar_id_t timevar;
struct timevar_time_def *elapsed;
{
struct timevar_def *tv = &timevars[timevar];
struct timevar_time_def now;
*elapsed = tv->elapsed;
if (tv->standalone)
{
get_time (&now);
timevar_accumulate (elapsed, &tv->start_time, &now);
}
else if (stack->timevar == tv)
{
get_time (&now);
timevar_accumulate (elapsed, &start_time, &now);
}
}
void
timevar_print (fp)
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)
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
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
putc ('\n', fp);
#endif
}
long
get_run_time ()
{
struct timevar_time_def total_elapsed;
timevar_get (TV_TOTAL, &total_elapsed);
return total_elapsed.user + total_elapsed.sys;
}
void
print_time (str, total)
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));
}