summaryrefslogtreecommitdiff
path: root/rts/sm/BlockAlloc.c
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2012-08-21 11:39:06 +0100
committerSimon Marlow <marlowsd@gmail.com>2012-08-21 11:50:45 +0100
commita68df77ede928e6c7790dacb5925625792a904d3 (patch)
tree86c01a0c730cdd04214e1b5802deb8b8cfb2e361 /rts/sm/BlockAlloc.c
parent0a7c5b891f9002b93f1cef3fe5b62aade89a6178 (diff)
downloadhaskell-a68df77ede928e6c7790dacb5925625792a904d3.tar.gz
Reduce fragmentation when using +RTS -H (with or without a size)
Diffstat (limited to 'rts/sm/BlockAlloc.c')
-rw-r--r--rts/sm/BlockAlloc.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/rts/sm/BlockAlloc.c b/rts/sm/BlockAlloc.c
index 8a1cfab966..9fd3ef577a 100644
--- a/rts/sm/BlockAlloc.c
+++ b/rts/sm/BlockAlloc.c
@@ -389,6 +389,41 @@ finish:
return bd;
}
+//
+// Allocate a chunk of blocks that is at most a megablock in size.
+// This API is used by the nursery allocator that wants contiguous
+// memory preferably, but doesn't require it. When memory is
+// fragmented we might have lots of large chunks that are less than a
+// full megablock, so allowing the nursery allocator to use these
+// reduces fragmentation considerably. e.g. on a GHC build with +RTS
+// -H, I saw fragmentation go from 17MB down to 3MB on a single compile.
+//
+bdescr *
+allocLargeChunk (void)
+{
+ bdescr *bd;
+ nat ln;
+
+ ln = 5; // start in the 32-63 block bucket
+ while (ln < MAX_FREE_LIST && free_list[ln] == NULL) {
+ ln++;
+ }
+ if (ln == MAX_FREE_LIST) {
+ return allocGroup(BLOCKS_PER_MBLOCK);
+ }
+ bd = free_list[ln];
+
+ n_alloc_blocks += bd->blocks;
+ if (n_alloc_blocks > hw_alloc_blocks) hw_alloc_blocks = n_alloc_blocks;
+
+ dbl_link_remove(bd, &free_list[ln]);
+ initGroup(bd);
+
+ IF_DEBUG(sanity, memset(bd->start, 0xaa, bd->blocks * BLOCK_SIZE));
+ IF_DEBUG(sanity, checkFreeListSanity());
+ return bd;
+}
+
bdescr *
allocGroup_lock(nat n)
{