summaryrefslogtreecommitdiff
path: root/rts/Schedule.c
diff options
context:
space:
mode:
authorsimonmar@microsoft.com <unknown>2008-02-28 15:31:29 +0000
committersimonmar@microsoft.com <unknown>2008-02-28 15:31:29 +0000
commitfac738e582dcaca1575f5291c83910db01d25284 (patch)
tree5c7645efcad551108137593e4cb19df259b4b7d4 /rts/Schedule.c
parent75927bb04bccb3ada850641939f0842a4168968a (diff)
downloadhaskell-fac738e582dcaca1575f5291c83910db01d25284.tar.gz
Release some of the memory allocated to a stack when it shrinks (#2090)
When a stack is occupying less than 1/4 of the memory it owns, and is larger than a megablock, we release half of it. Shrinking is O(1), it doesn't need to copy the stack.
Diffstat (limited to 'rts/Schedule.c')
-rw-r--r--rts/Schedule.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/rts/Schedule.c b/rts/Schedule.c
index caa19b26b3..5fa949cd4a 100644
--- a/rts/Schedule.c
+++ b/rts/Schedule.c
@@ -222,6 +222,7 @@ static Capability *scheduleDoGC(Capability *cap, Task *task,
static rtsBool checkBlackHoles(Capability *cap);
static StgTSO *threadStackOverflow(Capability *cap, StgTSO *tso);
+static StgTSO *threadStackUnderflow(Task *task, StgTSO *tso);
static void deleteThread (Capability *cap, StgTSO *tso);
static void deleteAllThreads (Capability *cap);
@@ -598,7 +599,7 @@ run_thread:
// ACTIVITY_DONE_GC means we turned off the timer signal to
// conserve power (see #1623). Re-enable it here.
nat prev;
- prev = xchg(&recent_activity, ACTIVITY_YES);
+ prev = xchg((P_)&recent_activity, ACTIVITY_YES);
if (prev == ACTIVITY_DONE_GC) {
startTimer();
}
@@ -683,6 +684,8 @@ run_thread:
schedulePostRunThread();
+ t = threadStackUnderflow(task,t);
+
ready_to_gc = rtsFalse;
switch (ret) {
@@ -2805,6 +2808,54 @@ threadStackOverflow(Capability *cap, StgTSO *tso)
return dest;
}
+static StgTSO *
+threadStackUnderflow (Task *task STG_UNUSED, StgTSO *tso)
+{
+ bdescr *bd, *new_bd;
+ lnat new_tso_size_w, tso_size_w;
+ StgTSO *new_tso;
+
+ tso_size_w = tso_sizeW(tso);
+
+ if (tso_size_w < MBLOCK_SIZE_W ||
+ (nat)(tso->stack + tso->stack_size - tso->sp) > tso->stack_size / 4)
+ {
+ return tso;
+ }
+
+ // don't allow throwTo() to modify the blocked_exceptions queue
+ // while we are moving the TSO:
+ lockClosure((StgClosure *)tso);
+
+ new_tso_size_w = round_to_mblocks(tso_size_w/2);
+
+ debugTrace(DEBUG_sched, "thread %ld: reducing TSO size from %lu words to %lu",
+ tso->id, tso_size_w, new_tso_size_w);
+
+ bd = Bdescr((StgPtr)tso);
+ new_bd = splitLargeBlock(bd, new_tso_size_w / BLOCK_SIZE_W);
+
+ new_tso = (StgTSO *)new_bd->start;
+ memcpy(new_tso,tso,TSO_STRUCT_SIZE);
+ new_tso->stack_size = new_tso_size_w - TSO_STRUCT_SIZEW;
+
+ tso->what_next = ThreadRelocated;
+ tso->_link = new_tso; // no write barrier reqd: same generation
+
+ // The TSO attached to this Task may have moved, so update the
+ // pointer to it.
+ if (task->tso == tso) {
+ task->tso = new_tso;
+ }
+
+ unlockTSO(new_tso);
+ unlockTSO(tso);
+
+ IF_DEBUG(sanity,checkTSO(new_tso));
+
+ return new_tso;
+}
+
/* ---------------------------------------------------------------------------
Interrupt execution
- usually called inside a signal handler so it mustn't do anything fancy.