Commit f939293c authored by simonm's avatar simonm
Browse files

[project @ 1999-01-28 15:04:00 by simonm]

- 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.
parent fa9f19cc
/* -----------------------------------------------------------------------------
* $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
......
/* -----------------------------------------------------------------------------
* $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)
{
......@@ -344,6 +382,69 @@ stgDeallocForGMP (void *ptr STG_UNUSED,
/* easy for us: the garbage collector does the dealloc'n */
}
/* -----------------------------------------------------------------------------
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
......@@ -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
/* -----------------------------------------------------------------------------
* $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 */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment