[commit: ghc] ghc-7.6: Some further tweaks to reduce fragmentation when allocating the nursery (33de4fb)

Paolo Capriotti <[email protected]>
Newsgroups gmane.comp.lang.haskell.cvs.ghc
Message-ID <[email protected]>
Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : ghc-7.6

http://hackage.haskell.org/trac/ghc/changeset/33de4fb027f90c188b1040bd930636a7e43b96b0

>---------------------------------------------------------------

commit 33de4fb027f90c188b1040bd930636a7e43b96b0
Author: Simon Marlow <[email protected]>
Date:   Fri Sep 7 13:36:09 2012 +0100

    Some further tweaks to reduce fragmentation when allocating the nursery
    
    MERGED from commit a8179622f84bbd52e127a9596d2d4a918ca64e0c

>---------------------------------------------------------------

 rts/sm/BlockAlloc.c |   48 ++++++++++++++++++++++++++++++++----------------
 rts/sm/BlockAlloc.h |    2 +-
 rts/sm/Storage.c    |    6 ++++--
 3 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/rts/sm/BlockAlloc.c b/rts/sm/BlockAlloc.c
index 5d1b1c0..93e06da 100644
--- a/rts/sm/BlockAlloc.c
+++ b/rts/sm/BlockAlloc.c
@@ -390,35 +390,51 @@ finish:
 }
 
 //
-// 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.
+// Allocate a chunk of blocks that is at least min and at most max
+// blocks 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)
+allocLargeChunk (nat min, nat max)
 {
     bdescr *bd;
-    nat ln;
+    nat ln, lnmax;
 
-    ln = 5; // start in the 32-63 block bucket
-    while (ln < MAX_FREE_LIST && free_list[ln] == NULL) {
+    if (min >= BLOCKS_PER_MBLOCK) {
+        return allocGroup(max);
+    }
+
+    ln = log_2_ceil(min);
+    lnmax = log_2_ceil(max); // tops out at MAX_FREE_LIST
+
+    while (ln < lnmax && free_list[ln] == NULL) {
         ln++;
     }
-    if (ln == MAX_FREE_LIST) {
-        return allocGroup(BLOCKS_PER_MBLOCK);
+    if (ln == lnmax) {
+        return allocGroup(max);
     }
     bd = free_list[ln];
 
+    if (bd->blocks <= max)              // exactly the right size!
+    {
+        dbl_link_remove(bd, &free_list[ln]);
+        initGroup(bd);
+    }
+    else   // block too big...
+    {                              
+        bd = split_free_block(bd, max, ln);
+        ASSERT(bd->blocks == max);
+        initGroup(bd);
+    }
+
     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;
diff --git a/rts/sm/BlockAlloc.h b/rts/sm/BlockAlloc.h
index d40cc42..1288e4d 100644
--- a/rts/sm/BlockAlloc.h
+++ b/rts/sm/BlockAlloc.h
@@ -11,7 +11,7 @@
 
 #include "BeginPrivate.h"
 
-bdescr *allocLargeChunk (void);
+bdescr *allocLargeChunk (nat min, nat max);
 
 /* Debugging  -------------------------------------------------------------- */
 
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index 45b6b89..e504c28 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -438,8 +438,10 @@ allocNursery (bdescr *tail, W_ blocks)
     // tiny optimisation (~0.5%), but it's free.
 
     while (blocks > 0) {
-        if (blocks >= BLOCKS_PER_MBLOCK) {
-            bd = allocLargeChunk(); // see comment with allocLargeChunk()
+        if (blocks >= BLOCKS_PER_MBLOCK / 4) {
+            n = stg_min(BLOCKS_PER_MBLOCK, blocks);
+            bd = allocLargeChunk(16, n); // see comment with allocLargeChunk()
+            // NB. we want a nice power of 2 for the minimum here
             n = bd->blocks;
         } else {
             bd = allocGroup(blocks);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.