diff options
author | Simon Marlow <marlowsd@gmail.com> | 2016-04-09 20:49:52 +0100 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2016-04-12 03:14:06 -0700 |
commit | f4446c5b963af8f3cc1693e2feab91dbe43d5237 (patch) | |
tree | 861d9bb9fea7086459bb734498348226e5d06019 /rts/sm/GCUtils.c | |
parent | 5c4cd0e44657d52f7ca5fee63f8765d17f1fbe85 (diff) | |
download | haskell-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.c | 49 |
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; |