Commit 6b109851 authored by Simon Marlow's avatar Simon Marlow

Time handling overhaul

Terminology cleanup: the type "Ticks" has been renamed "Time", which
is an StgWord64 in units of TIME_RESOLUTION (currently nanoseconds).
The terminology "tick" is now used consistently to mean the interval
between timer signals.

The ticker now always ticks in realtime (actually CLOCK_MONOTONIC if
we have it).  Before it used CPU time in the non-threaded RTS and
realtime in the threaded RTS, but I've discovered that the CPU timer
has terrible resolution (at least on Linux) and isn't much use for
profiling.  So now we always use realtime.  This should also fix

The default tick interval is now 10ms, except when profiling where we
drop it to 1ms.  This gives more accurate profiles without affecting
runtime too much (<1%).

Lots of cleanups - the resolution of Time is now in one place
only (Rts.h) rather than having calculations that depend on the
resolution scattered all over the RTS.  I hope I found them all.
parent 18aae185
......@@ -26,8 +26,11 @@ ghc_stage1_MORE_HC_OPTS = $(GhcStage1HcOpts)
ghc_stage2_MORE_HC_OPTS = $(GhcStage2HcOpts)
ghc_stage3_MORE_HC_OPTS = $(GhcStage3HcOpts)
ghc_stage2_CC_OPTS = -Iincludes
ghc_stage3_CC_OPTS = -Iincludes
# We need __GLASGOW_HASKELL__ in hschooks.c, so we have to build C
# sources with GHC:
ghc_stage1_UseGhcForCC = YES
ghc_stage2_UseGhcForCC = YES
ghc_stage3_UseGhcForCC = YES
ghc_stage1_C_FILES_NODEPS = ghc/hschooks.c
......
......@@ -23,7 +23,11 @@ defaultsHook (void)
// See #3408: the default idle GC time of 0.3s is too short on
// Windows where we receive console events once per second or so.
#if __GLASGOW_HASKELL__ >= 703
RtsFlags.GcFlags.idleGCDelayTime = SecondsToTime(5);
#else
RtsFlags.GcFlags.idleGCDelayTime = 5*1000;
#endif
}
void
......
......@@ -154,6 +154,36 @@ void _assertFail(const char *filename, unsigned int linenum)
#endif
#endif
/* -----------------------------------------------------------------------------
Time values in the RTS
-------------------------------------------------------------------------- */
// For most time values in the RTS we use a fixed resolution of nanoseconds,
// normalising the time we get from platform-dependent APIs to this
// resolution.
#define TIME_RESOLUTION 1000000000
typedef StgInt64 Time;
#if TIME_RESOLUTION == 1000000000
// I'm being lazy, but it's awkward to define fully general versions of these
#define TimeToUS(t) (t / 1000)
#define TimeToNS(t) (t)
#define USToTime(t) ((Time)(t) * 1000)
#define NSToTime(t) ((Time)(t))
#else
#error Fix TimeToNS(), TimeToUS() etc.
#endif
#define SecondsToTime(t) ((Time)(t) * TIME_RESOLUTION)
#define TimeToSeconds(t) ((t) / TIME_RESOLUTION)
// Use instead of SecondsToTime() when we have a floating-point
// seconds value, to avoid truncating it.
INLINE_HEADER Time fsecondsToTime (double t)
{
return (Time)(t * TIME_RESOLUTION);
}
/* -----------------------------------------------------------------------------
Include everything STG-ish
-------------------------------------------------------------------------- */
......
......@@ -52,7 +52,7 @@ struct GC_FLAGS {
rtsBool ringBell;
rtsBool frontpanel;
int idleGCDelayTime; /* in milliseconds */
Time idleGCDelayTime; /* units: TIME_RESOLUTION */
StgWord heapBase; /* address to ask the OS for memory */
};
......@@ -99,8 +99,8 @@ struct PROFILING_FLAGS {
# define HEAP_BY_CLOSURE_TYPE 8
nat profileInterval; /* delta between samples (in ms) */
nat profileIntervalTicks; /* delta between samples (in 'ticks') */
Time heapProfileInterval; /* time between samples */
nat heapProfileIntervalTicks; /* ticks between samples (derived) */
rtsBool includeTSOs;
......@@ -135,12 +135,21 @@ struct TRACE_FLAGS {
};
struct CONCURRENT_FLAGS {
int ctxtSwitchTime; /* in milliseconds */
int ctxtSwitchTicks; /* derived */
Time ctxtSwitchTime; /* units: TIME_RESOLUTION */
int ctxtSwitchTicks; /* derived */
};
/*
* The tickInterval is the time interval between "ticks", ie.
* timer signals (see Timer.{c,h}). It is the frequency at
* which we sample CCCS for profiling.
*
* It is changed by the +RTS -V<secs> flag.
*/
#define DEFAULT_TICK_INTERVAL USToTime(10000)
struct MISC_FLAGS {
int tickInterval; /* in milliseconds */
Time tickInterval; /* units: TIME_RESOLUTION */
rtsBool install_signal_handlers;
rtsBool machineReadable;
StgWord linkerMemBase; /* address to ask the OS for memory
......
......@@ -54,7 +54,13 @@ typedef union {
#if defined(mingw32_HOST_OS)
StgAsyncIOResult *async_result;
#endif
#if !defined(THREADED_RTS)
StgWord target;
// Only for the non-threaded RTS: the target time for a thread
// blocked in threadDelay, in units of 10ms. This is a
// compromise: we don't want to take up much space in the TSO. If
// you want better resolution for threadDelay, use -threaded.
#endif
} StgTSOBlockInfo;
......
......@@ -11,16 +11,10 @@
#include "BeginPrivate.h"
// We'll use a fixed resolution of usec for now. The machine
// dependent implementation may have a different resolution, but we'll
// normalise to this for the machine independent interface.
#define TICKS_PER_SECOND 1000000
typedef StgInt64 Ticks;
Ticks getProcessCPUTime (void);
Ticks getThreadCPUTime (void);
Ticks getProcessElapsedTime (void);
void getProcessTimes (Ticks *user, Ticks *elapsed);
Time getProcessCPUTime (void);
Time getThreadCPUTime (void);
Time getProcessElapsedTime (void);
void getProcessTimes (Time *user, Time *elapsed);
/* Get the current date and time.
Uses seconds since the Unix epoch, plus nanoseconds
......
......@@ -1785,16 +1785,13 @@ stg_delayzh
#else
W_ time;
W_ divisor;
(time) = foreign "C" getourtimeofday() [R1];
divisor = TO_W_(RtsFlags_MiscFlags_tickInterval(RtsFlags));
if (divisor == 0) {
divisor = 50;
}
divisor = divisor * 1000;
target = ((R1 + divisor - 1) / divisor) /* divide rounding up */
+ time + 1; /* Add 1 as getourtimeofday rounds down */
// getourtimeofday() returns a value in units of 10ms
// R1 is in microseconds, we need to (/ 10000), rounding up
target = time + 1 + (R1 + 10000-1) / 10000;
StgTSO_block_info(CurrentTSO) = target;
/* Insert the new thread in the sleeping queue. */
......
......@@ -1070,8 +1070,7 @@ heapCensusChain( Census *census, bdescr *bd )
}
}
void
heapCensus( Ticks t )
void heapCensus (Time t)
{
nat g, n;
Census *census;
......
......@@ -9,11 +9,9 @@
#ifndef PROFHEAP_H
#define PROFHEAP_H
#include "GetTime.h" // for Ticks
#include "BeginPrivate.h"
void heapCensus (Ticks t);
void heapCensus (Time t);
nat initHeapProfiling (void);
void endHeapProfiling (void);
rtsBool strMatchesSelector (char* str, char* sel);
......
......@@ -801,11 +801,11 @@ reportCCSProfiling( void )
fprintf(prof_file, " %s", prog_argv[count]);
fprintf(prof_file, "\n\n");
fprintf(prof_file, "\ttotal time = %11.2f secs (%lu ticks @ %d ms)\n",
(double) total_prof_ticks *
(double) RtsFlags.MiscFlags.tickInterval / 1000,
fprintf(prof_file, "\ttotal time = %11.2f secs (%lu ticks @ %d us)\n",
((double) total_prof_ticks *
(double) RtsFlags.MiscFlags.tickInterval) / TIME_RESOLUTION,
(unsigned long) total_prof_ticks,
(int) RtsFlags.MiscFlags.tickInterval);
(int) TimeToUS(RtsFlags.MiscFlags.tickInterval));
fprintf(prof_file, "\ttotal alloc = %11s bytes",
showStgWord64(total_alloc * sizeof(W_),
......
......@@ -50,7 +50,7 @@ void
startHeapProfTimer( void )
{
if (RtsFlags.ProfFlags.doHeapProfile &&
RtsFlags.ProfFlags.profileIntervalTicks > 0) {
RtsFlags.ProfFlags.heapProfileIntervalTicks > 0) {
do_heap_prof_ticks = rtsTrue;
}
}
......@@ -60,7 +60,7 @@ initProfTimer( void )
{
performHeapProfile = rtsFalse;
ticks_to_heap_profile = RtsFlags.ProfFlags.profileIntervalTicks;
ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks;
startHeapProfTimer();
}
......@@ -80,7 +80,7 @@ handleProfTick(void)
if (do_heap_prof_ticks) {
ticks_to_heap_profile--;
if (ticks_to_heap_profile <= 0) {
ticks_to_heap_profile = RtsFlags.ProfFlags.profileIntervalTicks;
ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks;
performHeapProfile = rtsTrue;
}
}
......
......@@ -113,7 +113,7 @@ void initRtsFlagsDefaults(void)
#ifdef RTS_GTK_FRONTPANEL
RtsFlags.GcFlags.frontpanel = rtsFalse;
#endif
RtsFlags.GcFlags.idleGCDelayTime = 300; /* millisecs */
RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
#if osf3_HOST_OS
/* ToDo: Perhaps by adjusting this value we can make linking without
......@@ -150,7 +150,7 @@ void initRtsFlagsDefaults(void)
#endif /* PROFILING */
RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
RtsFlags.ProfFlags.profileInterval = 100;
RtsFlags.ProfFlags. heapProfileInterval = USToTime(100000); // 100ms
#ifdef PROFILING
RtsFlags.ProfFlags.includeTSOs = rtsFalse;
......@@ -176,8 +176,13 @@ void initRtsFlagsDefaults(void)
RtsFlags.TraceFlags.user = rtsFalse;
#endif
RtsFlags.MiscFlags.tickInterval = 20; /* In milliseconds */
RtsFlags.ConcFlags.ctxtSwitchTime = 20; /* In milliseconds */
#ifdef PROFILING
// When profiling we want a lot more ticks
RtsFlags.MiscFlags.tickInterval = USToTime(1000); // 1ms
#else
RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
#endif
RtsFlags.ConcFlags.ctxtSwitchTime = USToTime(20000); // 20ms
RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
RtsFlags.MiscFlags.machineReadable = rtsFalse;
......@@ -312,9 +317,9 @@ usage_text[] = {
#if !defined(PROFILING)
"",
" -hT Heap residency profile (output file <program>.hp)",
" -h Heap residency profile (output file <program>.hp)",
#endif
" -i<sec> Time between heap samples (seconds, default: 0.1)",
" -i<sec> Time between heap profile samples (seconds, default: 0.1)",
"",
#if defined(TICKY_TICKY)
" -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
......@@ -322,10 +327,15 @@ usage_text[] = {
#endif
" -C<secs> Context-switch interval in seconds.",
" 0 or no argument means switch as often as possible.",
" Default: 0.02 sec; resolution is set by -V below.",
" -V<secs> Master tick interval in seconds (0 == disable timer).",
" This sets the resolution for -C and the profile timer -i.",
" Default: 0.02 sec.",
" -V<secs> Master tick interval in seconds (0 == disable timer).",
" This sets the resolution for -C and the heap profile timer -i,",
" and is the frequence of time profile samples.",
#ifdef PROFILING
" Default: 0.001 sec.",
#else
" Default: 0.01 sec.",
#endif
"",
#if defined(DEBUG)
" -Ds DEBUG: scheduler",
......@@ -884,11 +894,8 @@ error = rtsTrue;
if (rts_argv[arg][2] == '\0') {
/* use default */
} else {
I_ cst; /* tmp */
/* Convert to millisecs */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
RtsFlags.GcFlags.idleGCDelayTime = cst;
RtsFlags.GcFlags.idleGCDelayTime =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
......@@ -1090,12 +1097,9 @@ error = rtsTrue;
if (rts_argv[arg][2] == '\0') {
/* use default */
} else {
I_ cst; /* tmp */
/* Convert to milliseconds */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
RtsFlags.ProfFlags.profileInterval = cst;
}
RtsFlags.ProfFlags.heapProfileInterval =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
/* =========== CONCURRENT ========================= */
......@@ -1104,12 +1108,9 @@ error = rtsTrue;
if (rts_argv[arg][2] == '\0')
RtsFlags.ConcFlags.ctxtSwitchTime = 0;
else {
I_ cst; /* tmp */
/* Convert to milliseconds */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
RtsFlags.ConcFlags.ctxtSwitchTime = cst;
}
RtsFlags.ConcFlags.ctxtSwitchTime =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
case 'V': /* master tick interval */
......@@ -1118,11 +1119,8 @@ error = rtsTrue;
// turns off ticks completely
RtsFlags.MiscFlags.tickInterval = 0;
} else {
I_ cst; /* tmp */
/* Convert to milliseconds */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
RtsFlags.MiscFlags.tickInterval = cst;
RtsFlags.MiscFlags.tickInterval =
fsecondsToTime(atof(rts_argv[arg]+2));
}
break;
......@@ -1358,14 +1356,14 @@ error = rtsTrue;
static void normaliseRtsOpts (void)
{
if (RtsFlags.MiscFlags.tickInterval < 0) {
RtsFlags.MiscFlags.tickInterval = 50;
RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
}
// If the master timer is disabled, turn off the other timers.
if (RtsFlags.MiscFlags.tickInterval == 0) {
RtsFlags.ConcFlags.ctxtSwitchTime = 0;
RtsFlags.GcFlags.idleGCDelayTime = 0;
RtsFlags.ProfFlags.profileInterval = 0;
RtsFlags.ProfFlags.heapProfileInterval = 0;
}
// Determine what tick interval we should use for the RTS timer
......@@ -1383,9 +1381,9 @@ static void normaliseRtsOpts (void)
RtsFlags.MiscFlags.tickInterval);
}
if (RtsFlags.ProfFlags.profileInterval > 0) {
if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
RtsFlags.MiscFlags.tickInterval =
stg_min(RtsFlags.ProfFlags.profileInterval,
stg_min(RtsFlags.ProfFlags.heapProfileInterval,
RtsFlags.MiscFlags.tickInterval);
}
......@@ -1397,12 +1395,12 @@ static void normaliseRtsOpts (void)
RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
}
if (RtsFlags.ProfFlags.profileInterval > 0) {
RtsFlags.ProfFlags.profileIntervalTicks =
RtsFlags.ProfFlags.profileInterval /
if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
RtsFlags.ProfFlags.heapProfileIntervalTicks =
RtsFlags.ProfFlags.heapProfileInterval /
RtsFlags.MiscFlags.tickInterval;
} else {
RtsFlags.ProfFlags.profileIntervalTicks = 0;
RtsFlags.ProfFlags.heapProfileIntervalTicks = 0;
}
if (RtsFlags.GcFlags.stkChunkBufferSize >
......
......@@ -1304,7 +1304,7 @@ scheduleNeedHeapProfile( rtsBool ready_to_gc STG_UNUSED )
// When we have +RTS -i0 and we're heap profiling, do a census at
// every GC. This lets us get repeatable runs for debugging.
if (performHeapProfile ||
(RtsFlags.ProfFlags.profileInterval==0 &&
(RtsFlags.ProfFlags.heapProfileInterval==0 &&
RtsFlags.ProfFlags.doHeapProfile && ready_to_gc)) {
return rtsTrue;
} else {
......
......@@ -26,15 +26,15 @@
/* huh? */
#define BIG_STRING_LEN 512
#define TICK_TO_DBL(t) ((double)(t) / TICKS_PER_SECOND)
#define TimeToSecondsDbl(t) ((double)(t) / TIME_RESOLUTION)
static Ticks
static Time
start_init_cpu, start_init_elapsed,
end_init_cpu, end_init_elapsed,
start_exit_cpu, start_exit_elapsed,
end_exit_cpu, end_exit_elapsed;
static Ticks GC_tot_cpu = 0;
static Time GC_tot_cpu = 0;
static StgWord64 GC_tot_alloc = 0;
static StgWord64 GC_tot_copied = 0;
......@@ -43,11 +43,11 @@ static StgWord64 GC_par_max_copied = 0;
static StgWord64 GC_par_avg_copied = 0;
#ifdef PROFILING
static Ticks RP_start_time = 0, RP_tot_time = 0; // retainer prof user time
static Ticks RPe_start_time = 0, RPe_tot_time = 0; // retainer prof elap time
static Time RP_start_time = 0, RP_tot_time = 0; // retainer prof user time
static Time RPe_start_time = 0, RPe_tot_time = 0; // retainer prof elap time
static Ticks HC_start_time, HC_tot_time = 0; // heap census prof user time
static Ticks HCe_start_time, HCe_tot_time = 0; // heap census prof elap time
static Time HC_start_time, HC_tot_time = 0; // heap census prof user time
static Time HCe_start_time, HCe_tot_time = 0; // heap census prof elap time
#endif
#ifdef PROFILING
......@@ -66,9 +66,9 @@ static lnat max_slop = 0;
static lnat GC_end_faults = 0;
static Ticks *GC_coll_cpu = NULL;
static Ticks *GC_coll_elapsed = NULL;
static Ticks *GC_coll_max_pause = NULL;
static Time *GC_coll_cpu = NULL;
static Time *GC_coll_elapsed = NULL;
static Time *GC_coll_max_pause = NULL;
static void statsFlush( void );
static void statsClose( void );
......@@ -77,7 +77,7 @@ static void statsClose( void );
Current elapsed time
------------------------------------------------------------------------- */
Ticks stat_getElapsedTime(void)
Time stat_getElapsedTime(void)
{
return getProcessElapsedTime() - start_init_elapsed;
}
......@@ -87,9 +87,9 @@ Ticks stat_getElapsedTime(void)
------------------------------------------------------------------------ */
double
mut_user_time_until( Ticks t )
mut_user_time_until( Time t )
{
return TICK_TO_DBL(t - GC_tot_cpu);
return TimeToSecondsDbl(t - GC_tot_cpu);
// heapCensus() time is included in GC_tot_cpu, so we don't need
// to subtract it here.
}
......@@ -97,7 +97,7 @@ mut_user_time_until( Ticks t )
double
mut_user_time( void )
{
Ticks cpu;
Time cpu;
cpu = getProcessCPUTime();
return mut_user_time_until(cpu);
}
......@@ -110,13 +110,13 @@ mut_user_time( void )
double
mut_user_time_during_RP( void )
{
return TICK_TO_DBL(RP_start_time - GC_tot_cpu - RP_tot_time);
return TimeToSecondsDbl(RP_start_time - GC_tot_cpu - RP_tot_time);
}
double
mut_user_time_during_heap_census( void )
{
return TICK_TO_DBL(HC_start_time - GC_tot_cpu - RP_tot_time);
return TimeToSecondsDbl(HC_start_time - GC_tot_cpu - RP_tot_time);
}
#endif /* PROFILING */
......@@ -177,16 +177,16 @@ initStats1 (void)
statsPrintf(" bytes bytes bytes user elap user elap\n");
}
GC_coll_cpu =
(Ticks *)stgMallocBytes(
sizeof(Ticks)*RtsFlags.GcFlags.generations,
(Time *)stgMallocBytes(
sizeof(Time)*RtsFlags.GcFlags.generations,
"initStats");
GC_coll_elapsed =
(Ticks *)stgMallocBytes(
sizeof(Ticks)*RtsFlags.GcFlags.generations,
(Time *)stgMallocBytes(
sizeof(Time)*RtsFlags.GcFlags.generations,
"initStats");
GC_coll_max_pause =
(Ticks *)stgMallocBytes(
sizeof(Ticks)*RtsFlags.GcFlags.generations,
(Time *)stgMallocBytes(
sizeof(Time)*RtsFlags.GcFlags.generations,
"initStats");
for (i = 0; i < RtsFlags.GcFlags.generations; i++) {
GC_coll_cpu[i] = 0;
......@@ -299,7 +299,7 @@ stat_gcWorkerThreadStart (gc_thread *gct)
void
stat_gcWorkerThreadDone (gc_thread *gct)
{
Ticks thread_cpu, elapsed, gc_cpu, gc_elapsed;
Time thread_cpu, elapsed, gc_cpu, gc_elapsed;
if (RtsFlags.GcFlags.giveStats != NO_GC_STATS)
{
......@@ -326,7 +326,7 @@ stat_endGC (gc_thread *gct,
RtsFlags.ProfFlags.doHeapProfile)
// heap profiling needs GC_tot_time
{
Ticks cpu, elapsed, thread_gc_cpu, gc_cpu, gc_elapsed;
Time cpu, elapsed, thread_gc_cpu, gc_cpu, gc_elapsed;
getProcessTimes(&cpu, &elapsed);
gc_elapsed = elapsed - gct->gc_start_elapsed;
......@@ -344,10 +344,10 @@ stat_endGC (gc_thread *gct,
alloc*sizeof(W_), copied*sizeof(W_),
live*sizeof(W_));
statsPrintf(" %5.2f %5.2f %7.2f %7.2f %4ld %4ld (Gen: %2d)\n",
TICK_TO_DBL(gc_cpu),
TICK_TO_DBL(gc_elapsed),
TICK_TO_DBL(cpu),
TICK_TO_DBL(elapsed - start_init_elapsed),
TimeToSecondsDbl(gc_cpu),
TimeToSecondsDbl(gc_elapsed),
TimeToSecondsDbl(cpu),
TimeToSecondsDbl(elapsed - start_init_elapsed),
faults - gct->gc_start_faults,
gct->gc_start_faults - GC_end_faults,
gen);
......@@ -405,7 +405,7 @@ stat_endGC (gc_thread *gct,
void
stat_startRP(void)
{
Ticks user, elapsed;
Time user, elapsed;
getProcessTimes( &user, &elapsed );
RP_start_time = user;
......@@ -427,7 +427,7 @@ stat_endRP(
#endif
double averageNumVisit)
{
Ticks user, elapsed;
Time user, elapsed;
getProcessTimes( &user, &elapsed );
RP_tot_time += user - RP_start_time;
......@@ -450,7 +450,7 @@ stat_endRP(
void
stat_startHeapCensus(void)
{
Ticks user, elapsed;
Time user, elapsed;
getProcessTimes( &user, &elapsed );
HC_start_time = user;
......@@ -465,7 +465,7 @@ stat_startHeapCensus(void)
void
stat_endHeapCensus(void)
{
Ticks user, elapsed;
Time user, elapsed;
getProcessTimes( &user, &elapsed );
HC_tot_time += user - HC_start_time;
......@@ -516,27 +516,27 @@ StgInt TOTAL_CALLS=1;
statsPrintf(" (SLOW_CALLS_" #arity ") %% of (TOTAL_CALLS) : %.1f%%\n", \
SLOW_CALLS_##arity * 100.0/TOTAL_CALLS)
static inline Ticks get_init_cpu(void) { return end_init_cpu - start_init_cpu; }
static inline Ticks get_init_elapsed(void) { return end_init_elapsed - start_init_elapsed; }
static inline Time get_init_cpu(void) { return end_init_cpu - start_init_cpu; }
static inline Time get_init_elapsed(void) { return end_init_elapsed - start_init_elapsed; }
void
stat_exit(int alloc)
{
generation *gen;
Ticks gc_cpu = 0;
Ticks gc_elapsed = 0;
Ticks init_cpu = 0;
Ticks init_elapsed = 0;
Ticks mut_cpu = 0;
Ticks mut_elapsed = 0;
Ticks exit_cpu = 0;
Ticks exit_elapsed = 0;
Time gc_cpu = 0;
Time gc_elapsed = 0;
Time init_cpu = 0;
Time init_elapsed = 0;
Time mut_cpu = 0;
Time mut_elapsed = 0;
Time exit_cpu = 0;
Time exit_elapsed = 0;
if (RtsFlags.GcFlags.giveStats != NO_GC_STATS) {
char temp[BIG_STRING_LEN];
Ticks tot_cpu;
Ticks tot_elapsed;
Time tot_cpu;
Time tot_elapsed;
nat i, g, total_collections = 0;
getProcessTimes( &tot_cpu, &tot_elapsed );
......@@ -611,10 +611,10 @@ stat_exit(int alloc)
gen->no,
gen->collections,
gen->par_collections,
TICK_TO_DBL(GC_coll_cpu[g]),
TICK_TO_DBL(GC_coll_elapsed[g]),
gen->collections == 0 ? 0 : TICK_TO_DBL(GC_coll_elapsed[g] / gen->collections),
TICK_TO_DBL(GC_coll_max_pause[g]));
TimeToSecondsDbl(GC_coll_cpu[g]),
TimeToSecondsDbl(GC_coll_elapsed[g]),
gen->collections == 0 ? 0 : TimeToSecondsDbl(GC_coll_elapsed[g] / gen->collections),
TimeToSecondsDbl(GC_coll_max_pause[g]));
}
#if defined(THREADED_RTS)
......@@ -639,10 +639,10 @@ stat_exit(int alloc)
statsPrintf(" Task %2d %-8s : %6.2fs (%6.2fs) %6.2fs (%6.2fs)\n",
i,
(task->worker) ? "(worker)" : "(bound)",
TICK_TO_DBL(task->mut_time),
TICK_TO_DBL(task->mut_etime),
TICK_TO_DBL(task->gc_time),