diff options
author | Simon Marlow <marlowsd@gmail.com> | 2012-08-21 11:39:06 +0100 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2012-08-21 11:50:45 +0100 |
commit | a68df77ede928e6c7790dacb5925625792a904d3 (patch) | |
tree | 86c01a0c730cdd04214e1b5802deb8b8cfb2e361 /rts/sm/BlockAlloc.c | |
parent | 0a7c5b891f9002b93f1cef3fe5b62aade89a6178 (diff) | |
download | haskell-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.c | 35 |
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) { |