[project @ 1999-01-28 15:04:00 by simonm]
authorsimonm <unknown>
Thu, 28 Jan 1999 15:04:02 +0000 (15:04 +0000)
committersimonm <unknown>
Thu, 28 Jan 1999 15:04:02 +0000 (15:04 +0000)
- Be a bit more accurate about +RTS -H<size>, now we attempt to estimate
  the amount of memory that will be needed at the next GC based on
  the amount of promotion going on, and adjust the size of the allocation
  area appropriately.

- tidy up, move some stuff into Storage.c.

ghc/rts/GC.c
ghc/rts/Storage.c
ghc/rts/StoragePriv.h

index 6521312..17c056d 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.21 1999/01/27 16:41:14 simonm Exp $
+ * $Id: GC.c,v 1.22 1999/01/28 15:04:00 simonm Exp $
  *
  * Two-space garbage collector
  *
@@ -511,6 +511,9 @@ void GarbageCollect(void (*get_roots)(void))
     }
   }
   
+  /* Guess the amount of live data for stats. */
+  live = calcLive();
+
   /* Two-space collector:
    * Free the old to-space, and estimate the amount of live data.
    */
@@ -523,8 +526,6 @@ void GarbageCollect(void (*get_roots)(void))
     for (bd = g0s0->to_space; bd != NULL; bd = bd->link) {
       bd->evacuated = 0;       /* now from-space */
     }
-    live = g0s0->to_blocks * BLOCK_SIZE_W + 
-      ((lnat)g0s0->hp_bd->free - (lnat)g0s0->hp_bd->start) / sizeof(W_);
 
     /* For a two-space collector, we need to resize the nursery. */
     
@@ -563,71 +564,44 @@ void GarbageCollect(void (*get_roots)(void))
        blocks = RtsFlags.GcFlags.minAllocAreaSize;
       }
     }
+    resizeNursery(blocks);
     
-    if (nursery_blocks < blocks) {
-      IF_DEBUG(gc, fprintf(stderr, "Increasing size of nursery to %d blocks\n", 
-                          blocks));
-      g0s0->blocks = allocNursery(g0s0->blocks, blocks-nursery_blocks);
-    } else {
-      bdescr *next_bd;
-      
-      IF_DEBUG(gc, fprintf(stderr, "Decreasing size of nursery to %d blocks\n", 
-                          blocks));
-      for (bd = g0s0->blocks; nursery_blocks > blocks; nursery_blocks--) {
-       next_bd = bd->link;
-       freeGroup(bd);
-       bd = next_bd;
-      }
-      g0s0->blocks = bd;
-    }
-    
-    g0s0->n_blocks = nursery_blocks = blocks;
-
   } else {
     /* Generational collector:
-     * estimate the amount of live data, and adjust the allocation
-     * area size if the user has given us a suggestion (+RTS -H<blah>)
+     * If the user has given us a suggested heap size, adjust our
+     * allocation area to make best use of the memory available.
      */
 
-    live = 0;
-    for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
-      for (s = 0; s < generations[g].n_steps; s++) {
-       /* approximate amount of live data (doesn't take into account slop
-        * at end of each block).  ToDo: this more accurately.
-        */
-       if (g == 0 && s == 0) { continue; }
-       step = &generations[g].steps[s];
-       live += step->n_blocks * BLOCK_SIZE_W + 
-         ((lnat)step->hp_bd->free -(lnat)step->hp_bd->start) / sizeof(W_);
-      }
-    }
-
     if (RtsFlags.GcFlags.heapSizeSuggestion) {
-      nat avail_blocks = 
-       (RtsFlags.GcFlags.heapSizeSuggestion - live / BLOCK_SIZE_W) / 2;
-      nat blocks;
-      
-      if (avail_blocks > RtsFlags.GcFlags.minAllocAreaSize) {
-       blocks = avail_blocks;
+      int blocks;
+      nat needed = calcNeeded();       /* approx blocks needed at next GC */
+
+      /* Guess how much will be live in generation 0 step 0 next time.
+       * A good approximation is the amount of data that was live this
+       * time:  this assumes (1) that the size of G0S0 will be roughly
+       * the same as last time, and (2) that the promotion rate will be
+       * constant.
+       *
+       * If we don't know how much was live in G0S0 (because there's no
+       * step 1), then assume 30% (which is usually an overestimate).
+       */
+      if (g0->n_steps == 1) {
+       needed += (g0s0->n_blocks * 30) / 100;
       } else {
-       blocks = RtsFlags.GcFlags.minAllocAreaSize;
+       needed += g0->steps[1].n_blocks;
       }
 
-      if (blocks > g0s0->n_blocks) {
-       /* need to add some blocks on */
-       fprintf(stderr, "Increasing size of alloc area to %d blocks\n", blocks);
-       g0s0->blocks = allocNursery(g0s0->blocks, avail_blocks - g0s0->n_blocks);
-      } else {
-       bdescr *next_bd;
-       fprintf(stderr, "Decreasing size of alloc area to %d blocks\n", blocks);
-       for (bd = g0s0->blocks; nursery_blocks > blocks; nursery_blocks--) {
-         next_bd = bd->link;
-         freeGroup(bd);
-         bd = next_bd;
-       }
-       g0s0->blocks = bd;
+      /* Now we have a rough guess at the number of blocks needed for
+       * the next GC, subtract this from the user's suggested heap size
+       * and use the rest for the allocation area.
+       */
+      blocks = (int)RtsFlags.GcFlags.heapSizeSuggestion - (int)needed;
+      
+      if (blocks < (int)RtsFlags.GcFlags.minAllocAreaSize) {
+       blocks = RtsFlags.GcFlags.minAllocAreaSize;
       }
-      g0s0->n_blocks = nursery_blocks = blocks;
+      
+      resizeNursery((nat)blocks);
     }
   }
 
@@ -667,29 +641,9 @@ void GarbageCollect(void (*get_roots)(void))
   scheduleFinalisers(old_weak_ptr_list);
   
   /* check sanity after GC */
-#ifdef DEBUG
-  if (RtsFlags.GcFlags.generations == 1) {
-    IF_DEBUG(sanity, checkHeap(g0s0->to_space, NULL));
-    IF_DEBUG(sanity, checkChain(g0s0->large_objects));
-  } else {
-
-    for (g = 0; g <= N; g++) {
-      for (s = 0; s < generations[g].n_steps; s++) {
-       if (g == 0 && s == 0) { continue; }
-       IF_DEBUG(sanity, checkHeap(generations[g].steps[s].blocks, NULL));
-      }
-    }
-    for (g = N+1; g < RtsFlags.GcFlags.generations; g++) {
-      for (s = 0; s < generations[g].n_steps; s++) {
-       IF_DEBUG(sanity, checkHeap(generations[g].steps[s].blocks,
-                                  generations[g].steps[s].blocks->start));
-       IF_DEBUG(sanity, checkChain(generations[g].steps[s].large_objects));
-      }
-    }
-    IF_DEBUG(sanity, checkFreeListSanity());
-  }
-#endif
+  IF_DEBUG(sanity, checkSanity(N));
 
+  /* extra GC trace info */
   IF_DEBUG(gc, stat_describe_gens());
 
 #ifdef DEBUG
index 5117375..1f080c5 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Storage.c,v 1.7 1999/01/26 16:16:30 simonm Exp $
+ * $Id: Storage.c,v 1.8 1999/01/28 15:04:02 simonm Exp $
  *
  * Storage manager front end
  *
@@ -14,6 +14,7 @@
 #include "MBlock.h"
 #include "gmp.h"
 #include "Weak.h"
+#include "Sanity.h"
 
 #include "Storage.h"
 #include "StoragePriv.h"
@@ -50,6 +51,11 @@ initStorage (void)
   step *step;
   generation *gen;
 
+  if (RtsFlags.GcFlags.heapSizeSuggestion > 
+      RtsFlags.GcFlags.maxHeapSize) {
+    barf("Suggested heap size (-H<size>) is larger than max. heap size (-M<size>)\n");
+  }
+
   initBlockAllocator();
   
   /* allocate generation info array */
@@ -171,6 +177,38 @@ allocNursery (bdescr *last_bd, nat blocks)
   return last_bd;
 }
 
+extern void
+resizeNursery ( nat blocks )
+{
+  bdescr *bd;
+
+  if (nursery_blocks == blocks) {
+    ASSERT(g0s0->n_blocks == blocks);
+    return;
+  }
+
+  else if (nursery_blocks < blocks) {
+    IF_DEBUG(gc, fprintf(stderr, "Increasing size of nursery to %d blocks\n", 
+                        blocks));
+    g0s0->blocks = allocNursery(g0s0->blocks, blocks-nursery_blocks);
+  } 
+
+  else {
+    bdescr *next_bd;
+    
+    IF_DEBUG(gc, fprintf(stderr, "Decreasing size of nursery to %d blocks\n", 
+                        blocks));
+    for (bd = g0s0->blocks; nursery_blocks > blocks; nursery_blocks--) {
+      next_bd = bd->link;
+      freeGroup(bd);
+      bd = next_bd;
+    }
+    g0s0->blocks = bd;
+  }
+  
+  g0s0->n_blocks = nursery_blocks = blocks;
+}
+
 void
 exitStorage (void)
 {
@@ -345,6 +383,69 @@ stgDeallocForGMP (void *ptr STG_UNUSED,
 }
 
 /* -----------------------------------------------------------------------------
+   Stats and stuff
+   -------------------------------------------------------------------------- */
+
+/* Approximate the amount of live data in the heap.  To be called just
+ * after garbage collection (see GarbageCollect()).
+ */
+extern lnat 
+calcLive(void)
+{
+  nat g, s;
+  lnat live = 0;
+  step *step;
+
+  if (RtsFlags.GcFlags.generations == 1) {
+    live = g0s0->to_blocks * BLOCK_SIZE_W + 
+      ((lnat)g0s0->hp_bd->free - (lnat)g0s0->hp_bd->start) / sizeof(W_);
+  }
+
+  for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+    for (s = 0; s < generations[g].n_steps; s++) {
+      /* approximate amount of live data (doesn't take into account slop
+        * at end of each block).
+        */
+      if (g == 0 && s == 0) { 
+         continue; 
+      }
+      step = &generations[g].steps[s];
+      live += step->n_blocks * BLOCK_SIZE_W + 
+       ((lnat)step->hp_bd->free -(lnat)step->hp_bd->start) / sizeof(W_);
+    }
+  }
+  return live;
+}
+
+/* Approximate the number of blocks that will be needed at the next
+ * garbage collection.
+ *
+ * Assume: all data currently live will remain live.  Steps that will
+ * be collected next time will therefore need twice as many blocks
+ * since all the data will be copied.
+ */
+extern lnat 
+calcNeeded(void)
+{
+  lnat needed = 0;
+  nat g, s;
+  step *step;
+
+  for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+    for (s = 0; s < generations[g].n_steps; s++) {
+      if (g == 0 && s == 0) { continue; }
+      step = &generations[g].steps[s];
+      if (generations[g].steps[0].n_blocks > generations[g].max_blocks) {
+       needed += 2 * step->n_blocks;
+      } else {
+       needed += step->n_blocks;
+      }
+    }
+  }
+  return needed;
+}
+
+/* -----------------------------------------------------------------------------
    Debugging
 
    memInventory() checks for memory leaks by counting up all the
@@ -409,4 +510,33 @@ memInventory(void)
 #endif
 }
 
+/* Full heap sanity check. */
+
+extern void
+checkSanity(nat N)
+{
+  nat g, s;
+
+  if (RtsFlags.GcFlags.generations == 1) {
+    checkHeap(g0s0->to_space, NULL);
+    checkChain(g0s0->large_objects);
+  } else {
+    
+    for (g = 0; g <= N; g++) {
+      for (s = 0; s < generations[g].n_steps; s++) {
+       if (g == 0 && s == 0) { continue; }
+       checkHeap(generations[g].steps[s].blocks, NULL);
+      }
+    }
+    for (g = N+1; g < RtsFlags.GcFlags.generations; g++) {
+      for (s = 0; s < generations[g].n_steps; s++) {
+       checkHeap(generations[g].steps[s].blocks,
+                 generations[g].steps[s].blocks->start);
+       checkChain(generations[g].steps[s].large_objects);
+      }
+    }
+    checkFreeListSanity();
+  }
+}
+
 #endif
index defe142..1c3266c 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: StoragePriv.h,v 1.5 1999/01/19 17:06:05 simonm Exp $
+ * $Id: StoragePriv.h,v 1.6 1999/01/28 15:04:02 simonm Exp $
  *
  * Internal Storage Manger Interface
  *
@@ -106,7 +106,11 @@ extern nat nursery_blocks;
 extern nat alloc_blocks;
 extern nat alloc_blocks_lim;
 
-extern bdescr *allocNursery (bdescr *last_bd, nat blocks);
+extern bdescr *allocNursery ( bdescr *last_bd, nat blocks );
+extern void resizeNursery ( nat blocks );
+
+extern lnat calcLive( void );
+extern lnat calcNeeded( void );
 
 static inline void
 dbl_link_onto(bdescr *bd, bdescr **list)
@@ -127,6 +131,7 @@ dbl_link_onto(bdescr *bd, bdescr **list)
 
 #ifdef DEBUG
 extern void memInventory(void);
+extern void checkSanity(nat N);
 #endif
 
 #endif /* STORAGEPRIV_H */