/* -----------------------------------------------------------------------------
- * $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
*
}
}
+ /* 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.
*/
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. */
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);
}
}
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
/* -----------------------------------------------------------------------------
- * $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
*
#include "MBlock.h"
#include "gmp.h"
#include "Weak.h"
+#include "Sanity.h"
#include "Storage.h"
#include "StoragePriv.h"
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 */
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)
{
}
/* -----------------------------------------------------------------------------
+ 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
#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