summaryrefslogtreecommitdiff
path: root/rts/Apply.cmm
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2010-12-15 12:08:43 +0000
committerSimon Marlow <marlowsd@gmail.com>2010-12-15 12:08:43 +0000
commitf30d527344db528618f64a25250a3be557d9f287 (patch)
tree5b827afed254139a197cbdcdd37bebe8fa859d67 /rts/Apply.cmm
parent99b6e6ac44c6c610b0d60e3b70a2341c83d23106 (diff)
downloadhaskell-f30d527344db528618f64a25250a3be557d9f287.tar.gz
Implement stack chunks and separate TSO/STACK objects
This patch makes two changes to the way stacks are managed: 1. The stack is now stored in a separate object from the TSO. This means that it is easier to replace the stack object for a thread when the stack overflows or underflows; we don't have to leave behind the old TSO as an indirection any more. Consequently, we can remove ThreadRelocated and deRefTSO(), which were a pain. This is obviously the right thing, but the last time I tried to do it it made performance worse. This time I seem to have cracked it. 2. Stacks are now represented as a chain of chunks, rather than a single monolithic object. The big advantage here is that individual chunks are marked clean or dirty according to whether they contain pointers to the young generation, and the GC can avoid traversing clean stack chunks during a young-generation collection. This means that programs with deep stacks will see a big saving in GC overhead when using the default GC settings. A secondary advantage is that there is much less copying involved as the stack grows. Programs that quickly grow a deep stack will see big improvements. In some ways the implementation is simpler, as nothing special needs to be done to reclaim stack as the stack shrinks (the GC just recovers the dead stack chunks). On the other hand, we have to manage stack underflow between chunks, so there's a new stack frame (UNDERFLOW_FRAME), and we now have separate TSO and STACK objects. The total amount of code is probably about the same as before. There are new RTS flags: -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m -kc<size> Sets the stack chunk size (default 32k) -kb<size> Sets the stack chunk buffer size (default 1k) -ki was previously called just -k, and the old name is still accepted for backwards compatibility. These new options are documented.
Diffstat (limited to 'rts/Apply.cmm')
-rw-r--r--rts/Apply.cmm53
1 files changed, 53 insertions, 0 deletions
diff --git a/rts/Apply.cmm b/rts/Apply.cmm
index 9af9b11a97..f9ac3b353c 100644
--- a/rts/Apply.cmm
+++ b/rts/Apply.cmm
@@ -350,3 +350,56 @@ for:
ENTER();
}
+
+/* -----------------------------------------------------------------------------
+ AP_STACK_NOUPD - exactly like AP_STACK, but doesn't push an update frame.
+ -------------------------------------------------------------------------- */
+
+INFO_TABLE(stg_AP_STACK_NOUPD,/*special layout*/0,0,AP_STACK,
+ "AP_STACK_NOUPD","AP_STACK_NOUPD")
+{
+ W_ Words;
+ W_ ap;
+
+ ap = R1;
+
+ Words = StgAP_STACK_size(ap);
+
+ /*
+ * Check for stack overflow. IMPORTANT: use a _NP check here,
+ * because if the check fails, we might end up blackholing this very
+ * closure, in which case we must enter the blackhole on return rather
+ * than continuing to evaluate the now-defunct closure.
+ */
+ STK_CHK_NP(WDS(Words) + WDS(AP_STACK_SPLIM));
+ /* ensure there is at least AP_STACK_SPLIM words of headroom available
+ * after unpacking the AP_STACK. See bug #1466 */
+
+ Sp = Sp - WDS(Words);
+
+ TICK_ENT_AP();
+ LDV_ENTER(ap);
+
+ // Enter PAP cost centre
+ ENTER_CCS_PAP_CL(ap); // ToDo: ENTER_CC_AP_CL
+
+ // Reload the stack
+ W_ i;
+ W_ p;
+ p = ap + SIZEOF_StgHeader + OFFSET_StgAP_STACK_payload;
+ i = 0;
+for:
+ if (i < Words) {
+ Sp(i) = W_[p];
+ p = p + WDS(1);
+ i = i + 1;
+ goto for;
+ }
+
+ // Off we go!
+ TICK_ENT_VIA_NODE();
+
+ R1 = StgAP_STACK_fun(ap);
+
+ ENTER();
+}