</sect2>
+ <sect2 id="rts-options-misc">
+ <title>Miscellaneous RTS options</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-V<replaceable>secs</replaceable></option></term>
+ <indexterm><primary><option>-V</option></primary><secondary>RTS
+ option</secondary></indexterm>
+ <listitem>
+ <para>Sets the interval that the RTS clock ticks at. The
+ runtime uses a single timer signal to count ticks; this timer
+ signal is used to control the context switch timer (<xref
+ linkend="sec-using-concurrent" />) and the heap profiling
+ timer <xref linkend="rts-options-heap-prof" />. Also, the
+ time profiler uses the RTS timer signal directly to record
+ time profiling samples.</para>
+
+ <para>Normally, setting the <option>-V</option> option
+ directly is not necessary: the resolution of the RTS timer is
+ adjusted automatically if a short interval is requested with
+ the <option>-C</option> or <option>-i</option> options.
+ However, setting <option>-V</option> is required in order to
+ increase the resolution of the time profiler.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
<sect2 id="rts-options-gc">
<title>RTS options to control the garbage collector</title>
every 4k of allocation). With <option>-C0</option> or
<option>-C</option>, context switches will occur as often as
possible (at every heap block allocation). By default, context
- switches occur every 20ms. Note that GHC's internal timer ticks
- every 20ms, and the context switch timer is always a multiple of
- this timer, so 20ms is the maximum granularity available for timed
- context switches.</para>
+ switches occur every 20ms.</para>
</listitem>
</varlistentry>
</variablelist>
Misc junk
-------------------------------------------------------------------------- */
-#define TICK_MILLISECS (1000/TICK_FREQUENCY) /* ms per tick */
-
#define NO_TREC stg_NO_TREC_closure
#define END_TSO_QUEUE stg_END_TSO_QUEUE_closure
rtsBool ringBell;
rtsBool frontpanel;
- int idleGCDelayTicks; /* in milliseconds */
+ int idleGCDelayTime; /* in milliseconds */
};
struct DEBUG_FLAGS {
int ctxtSwitchTicks; /* derived */
};
+struct MISC_FLAGS {
+ int tickInterval; /* in milliseconds */
+};
+
#ifdef PAR
/* currently the same as GRAN_STATS_FLAGS */
struct PAR_STATS_FLAGS {
/* The first portion of RTS_FLAGS is invariant. */
struct GC_FLAGS GcFlags;
struct CONCURRENT_FLAGS ConcFlags;
+ struct MISC_FLAGS MiscFlags;
struct DEBUG_FLAGS DebugFlags;
struct COST_CENTRE_FLAGS CcFlags;
struct PROFILING_FLAGS ProfFlags;
RTS_FLAGS, DebugFlags.weak);
struct_field_("RtsFlags_GcFlags_initialStkSize",
RTS_FLAGS, GcFlags.initialStkSize);
+ struct_field_("RtsFlags_MiscFlags_tickInterval",
+ RTS_FLAGS, MiscFlags.tickInterval);
struct_size(StgFunInfoExtraFwd);
struct_field(StgFunInfoExtraFwd, slow_apply);
#else
W_ time;
- time = foreign "C" getourtimeofday();
- target = (R1 / (TICK_MILLISECS*1000)) + time;
+ time = foreign "C" getourtimeofday() [R1];
+ target = (R1 / (TO_W_(RtsFlags_MiscFlags_tickInterval(RtsFlags))*1000)) + time;
StgTSO_block_info(CurrentTSO) = target;
/* Insert the new thread in the sleeping queue. */
if (RtsFlags.CcFlags.doCostCentres == COST_CENTRES_XML) {
/* dump the time, and the profiling interval */
fprintf(prof_file, "\"%s\"\n", time_str());
- fprintf(prof_file, "\"%d ms\"\n", TICK_MILLISECS);
+ fprintf(prof_file, "\"%d ms\"\n", RtsFlags.MiscFlags.tickInterval);
/* declare all the cost centres */
{
fprintf(prof_file, "\n\n");
fprintf(prof_file, "\ttotal time = %11.2f secs (%lu ticks @ %d ms)\n",
- total_prof_ticks / (StgFloat) TICK_FREQUENCY,
- total_prof_ticks, TICK_MILLISECS);
+ (double) total_prof_ticks *
+ (double) RtsFlags.MiscFlags.tickInterval / 1000,
+ (unsigned long) total_prof_ticks,
+ (int) RtsFlags.MiscFlags.tickInterval);
fprintf(prof_file, "\ttotal alloc = %11s bytes",
ullong_format_string(total_alloc * sizeof(W_),
{
performHeapProfile = rtsFalse;
- RtsFlags.ProfFlags.profileIntervalTicks =
- RtsFlags.ProfFlags.profileInterval / TICK_MILLISECS;
-
ticks_to_heap_profile = RtsFlags.ProfFlags.profileIntervalTicks;
startHeapProfTimer();
#include "RtsFlags.h"
#include "RtsUtils.h"
#include "BlockAlloc.h"
-#include "Timer.h" /* CS_MIN_MILLISECS */
#include "Profiling.h"
#ifdef HAVE_CTYPE_H
#ifdef RTS_GTK_FRONTPANEL
RtsFlags.GcFlags.frontpanel = rtsFalse;
#endif
- RtsFlags.GcFlags.idleGCDelayTicks = 300 / TICK_MILLISECS; /* ticks */
+ RtsFlags.GcFlags.idleGCDelayTime = 300; /* millisecs */
#ifdef DEBUG
RtsFlags.DebugFlags.scheduler = rtsFalse;
RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
#endif
- RtsFlags.ConcFlags.ctxtSwitchTime = CS_MIN_MILLISECS; /* In milliseconds */
+ RtsFlags.MiscFlags.tickInterval = 50; /* In milliseconds */
+ RtsFlags.ConcFlags.ctxtSwitchTime = 50; /* In milliseconds */
#ifdef THREADED_RTS
RtsFlags.ParFlags.nNodes = 1;
} else {
I_ cst; /* tmp */
- /* Convert to ticks */
+ /* Convert to millisecs */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
- if (cst > 0 && cst < TICK_MILLISECS) {
- cst = TICK_MILLISECS;
- } else {
- cst = cst / TICK_MILLISECS;
- }
- RtsFlags.GcFlags.idleGCDelayTicks = cst;
+ RtsFlags.GcFlags.idleGCDelayTime = cst;
}
break;
/* Convert to milliseconds */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
- cst = (cst / CS_MIN_MILLISECS) * CS_MIN_MILLISECS;
- if (cst != 0 && cst < CS_MIN_MILLISECS)
- cst = CS_MIN_MILLISECS;
-
RtsFlags.ProfFlags.profileInterval = cst;
}
break;
/* Convert to milliseconds */
cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
- cst = (cst / CS_MIN_MILLISECS) * CS_MIN_MILLISECS;
- if (cst != 0 && cst < CS_MIN_MILLISECS)
- cst = CS_MIN_MILLISECS;
-
RtsFlags.ConcFlags.ctxtSwitchTime = cst;
}
break;
+ case 'V': /* master tick interval */
+ if (rts_argv[arg][2] == '\0') {
+ // 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;
+ }
+ break;
+
#if defined(THREADED_RTS) && !defined(NOSMP)
case 'N':
THREADED_BUILD_ONLY(
}
}
}
+
+ // Determine what tick interval we should use for the RTS timer
+ // by taking the shortest of the various intervals that we need to
+ // monitor.
+ if (RtsFlags.MiscFlags.tickInterval <= 0) {
+ RtsFlags.MiscFlags.tickInterval = 50;
+ }
+
+ if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
+ RtsFlags.MiscFlags.tickInterval =
+ stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
+ RtsFlags.MiscFlags.tickInterval);
+ }
+
+ if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
+ RtsFlags.MiscFlags.tickInterval =
+ stg_min(RtsFlags.GcFlags.idleGCDelayTime,
+ RtsFlags.MiscFlags.tickInterval);
+ }
+
+#ifdef PROFILING
+ if (RtsFlags.ProfFlags.profileInterval > 0) {
+ RtsFlags.MiscFlags.tickInterval =
+ stg_min(RtsFlags.ProfFlags.profileInterval,
+ RtsFlags.MiscFlags.tickInterval);
+ }
+#endif
+
+ if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
+ RtsFlags.ConcFlags.ctxtSwitchTicks =
+ RtsFlags.ConcFlags.ctxtSwitchTime /
+ RtsFlags.MiscFlags.tickInterval;
+ } else {
+ RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
+ }
+
+#ifdef PROFILING
+ RtsFlags.ProfFlags.profileIntervalTicks =
+ RtsFlags.ProfFlags.profileInterval / RtsFlags.MiscFlags.tickInterval;
+#endif
+
if (error) {
const char **p;
#endif
/* start the virtual timer 'subsystem'. */
- startTimer(TICK_MILLISECS);
+ startTimer();
/* Initialise the stats department */
initStats();
context_switch = 0;
sched_state = SCHED_RUNNING;
- RtsFlags.ConcFlags.ctxtSwitchTicks =
- RtsFlags.ConcFlags.ctxtSwitchTime / TICK_MILLISECS;
-
#if defined(THREADED_RTS)
/* Initialise the mutex and condition variables used by
* the scheduler. */
#if defined(THREADED_RTS)
/*
- * If we've been inactive for idleGCDelayTicks (set by +RTS
+ * If we've been inactive for idleGCDelayTime (set by +RTS
* -I), tell the scheduler to wake up and do a GC, to check
* for threads that are deadlocked.
*/
switch (recent_activity) {
case ACTIVITY_YES:
recent_activity = ACTIVITY_MAYBE_NO;
- ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTicks;
+ ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTime /
+ RtsFlags.MiscFlags.tickInterval;
break;
case ACTIVITY_MAYBE_NO:
if (ticks_to_gc == 0) break; /* 0 ==> no idle GC */
ticks_to_gc--;
if (ticks_to_gc == 0) {
- ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTicks;
+ ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTime /
+ RtsFlags.MiscFlags.tickInterval;
recent_activity = ACTIVITY_INACTIVE;
blackholes_need_checking = rtsTrue;
/* hack: re-use the blackholes_need_checking flag */
}
int
-startTimer(nat ms)
+startTimer(void)
{
#ifdef PROFILING
initProfTimer();
#endif
- return startTicker(ms, handle_tick);
+ return startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
}
int
-stopTimer()
+stopTimer(void)
{
return stopTicker();
}
/* -----------------------------------------------------------------------------
*
- * (c) The GHC Team, 1995-2005
+ * (c) The GHC Team, 1995-2006
*
* Interval timer service for profiling and pre-emptive scheduling.
*
#ifndef TIMER_H
#define TIMER_H
-# define TICK_MILLISECS (1000/TICK_FREQUENCY) /* ms per tick */
-
-/* Context switch timing constants. Context switches happen after a
- * whole number of ticks, the default being every tick.
- */
-#define CS_MIN_MILLISECS TICK_MILLISECS /* milliseconds per slice */
-
typedef void (*TickProc)(int);
-extern int startTimer(nat ms);
+extern int startTimer(void);
extern int stopTimer(void);
#endif /* TIMER_H */
struct timeval tv;
gettimeofday(&tv, (struct timezone *) NULL);
// cast to lnat because nat may be 64 bit when int is only 32 bit
- return ((lnat)tv.tv_sec * TICK_FREQUENCY +
- (lnat)tv.tv_usec * TICK_FREQUENCY / 1000000);
+ return ((lnat)tv.tv_sec * 1000 / RtsFlags.MiscFlags.tickInterval +
+ (lnat)tv.tv_usec / (RtsFlags.MiscFlags.tickInterval * 1000));
}
min = 0;
} else if (sleeping_queue != END_TSO_QUEUE) {
min = (sleeping_queue->block_info.target - ticks)
- * TICK_MILLISECS * 1000;
+ * RtsFlags.MiscFlags.tickInterval * 1000;
} else {
min = 0x7ffffff;
}