summaryrefslogtreecommitdiff
path: root/rts/sm/GCUtils.c
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2016-04-09 20:49:52 +0100
committerSimon Marlow <marlowsd@gmail.com>2016-04-12 03:14:06 -0700
commitf4446c5b963af8f3cc1693e2feab91dbe43d5237 (patch)
tree861d9bb9fea7086459bb734498348226e5d06019 /rts/sm/GCUtils.c
parent5c4cd0e44657d52f7ca5fee63f8765d17f1fbe85 (diff)
downloadhaskell-f4446c5b963af8f3cc1693e2feab91dbe43d5237.tar.gz
Allocate blocks in the GC in batches
Avoids contention for the block allocator lock in the GC; this can be seen in the gc_alloc_block_sync counter emitted by +RTS -s. I experimented with this a while ago, and there was already commented-out code for it in GCUtils.c, but I've now improved it so that it doesn't result in significantly worse memory usage. * The old method of putting spare blocks on ws->part_list was wasteful, the spare blocks are now shared between all generations and retained between GCs. * repeated allocGroup() results in fragmentation, so I switched to using allocLargeChunk() instead which is fragmentation-friendly; we already use it for the same reason in nursery allocation.
Diffstat (limited to 'rts/sm/GCUtils.c')
-rw-r--r--rts/sm/GCUtils.c49
1 files changed, 22 insertions, 27 deletions
diff --git a/rts/sm/GCUtils.c b/rts/sm/GCUtils.c
index 364a10a759..9ecb674bb3 100644
--- a/rts/sm/GCUtils.c
+++ b/rts/sm/GCUtils.c
@@ -51,29 +51,28 @@ allocGroup_sync(nat n)
}
-#if 0
-static void
-allocBlocks_sync(nat n, bdescr **hd, bdescr **tl,
- nat gen_no, step *stp,
- StgWord32 flags)
+static nat
+allocBlocks_sync(nat n, bdescr **hd)
{
bdescr *bd;
nat i;
ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync);
- bd = allocGroup(n);
+ bd = allocLargeChunk(1,n);
+ // NB. allocLargeChunk, rather than allocGroup(n), to allocate in a
+ // fragmentation-friendly way.
+ n = bd->blocks;
for (i = 0; i < n; i++) {
bd[i].blocks = 1;
- bd[i].gen_no = gen_no;
- bd[i].step = stp;
- bd[i].flags = flags;
bd[i].link = &bd[i+1];
- bd[i].u.scan = bd[i].free = bd[i].start;
+ bd[i].free = bd[i].start;
}
- *hd = bd;
- *tl = &bd[n-1];
+ bd[n-1].link = NULL;
+ // We have to hold the lock until we've finished fiddling with the metadata,
+ // otherwise the block allocator can get confused.
RELEASE_SPIN_LOCK(&gc_alloc_block_sync);
+ *hd = bd;
+ return n;
}
-#endif
void
freeChain_sync(bdescr *bd)
@@ -312,26 +311,22 @@ alloc_todo_block (gen_workspace *ws, nat size)
}
else
{
- // blocks in to-space get the BF_EVACUATED flag.
-
-// allocBlocks_sync(16, &hd, &tl,
-// ws->step->gen_no, ws->step, BF_EVACUATED);
-//
-// tl->link = ws->part_list;
-// ws->part_list = hd->link;
-// ws->n_part_blocks += 15;
-//
-// bd = hd;
-
if (size > BLOCK_SIZE_W) {
bd = allocGroup_sync((W_)BLOCK_ROUND_UP(size*sizeof(W_))
/ BLOCK_SIZE);
} else {
- bd = allocBlock_sync();
+ if (gct->free_blocks) {
+ bd = gct->free_blocks;
+ gct->free_blocks = bd->link;
+ } else {
+ allocBlocks_sync(16, &bd);
+ gct->free_blocks = bd->link;
+ }
}
- initBdescr(bd, ws->gen, ws->gen->to);
+ // blocks in to-space get the BF_EVACUATED flag.
bd->flags = BF_EVACUATED;
- bd->u.scan = bd->free = bd->start;
+ bd->u.scan = bd->start;
+ initBdescr(bd, ws->gen, ws->gen->to);
}
bd->link = NULL;