/* -----------------------------------------------------------------------------
- * $Id: Storage.c,v 1.44 2001/08/08 10:50:37 simonmar Exp $
+ * $Id: Storage.c,v 1.54 2001/11/22 14:25:12 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
*
* ---------------------------------------------------------------------------*/
+#include "PosixSource.h"
#include "Rts.h"
#include "RtsUtils.h"
#include "RtsFlags.h"
#include "MBlock.h"
#include "Weak.h"
#include "Sanity.h"
+#include "Arena.h"
#include "Storage.h"
#include "Schedule.h"
#include "StoragePriv.h"
-#ifndef SMP
-nat nursery_blocks; /* number of blocks in the nursery */
-#endif
+#include "RetainerProfile.h" // for counting memory blocks (memInventory)
StgClosure *caf_list = NULL;
static void stgDeallocForGMP (void *ptr, size_t size);
void
-initStorage (void)
+initStorage( void )
{
nat g, s;
step *stp;
generation *gen;
- /* If we're doing heap profiling, we want a two-space heap with a
- * fixed-size allocation area so that we get roughly even-spaced
- * samples.
- */
-
- /* As an experiment, try a 2 generation collector
- */
-
-#if defined(PROFILING) || defined(DEBUG)
- if (RtsFlags.ProfFlags.doHeapProfile) {
- RtsFlags.GcFlags.generations = 1;
- RtsFlags.GcFlags.steps = 1;
- RtsFlags.GcFlags.oldGenFactor = 0;
- RtsFlags.GcFlags.heapSizeSuggestion = 0;
+ if (RtsFlags.GcFlags.maxHeapSize != 0 &&
+ RtsFlags.GcFlags.heapSizeSuggestion >
+ RtsFlags.GcFlags.maxHeapSize) {
+ RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
}
-#endif
- if (RtsFlags.GcFlags.heapSizeSuggestion >
+ if (RtsFlags.GcFlags.maxHeapSize != 0 &&
+ RtsFlags.GcFlags.minAllocAreaSize >
RtsFlags.GcFlags.maxHeapSize) {
- RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
+ prog_belch("maximum heap size (-M) is smaller than minimum alloc area size (-A)");
+ exit(1);
}
initBlockAllocator();
stp->scan = NULL;
stp->scan_bd = NULL;
stp->large_objects = NULL;
+ stp->n_large_blocks = 0;
stp->new_large_objects = NULL;
stp->scavenged_large_objects = NULL;
+ stp->n_scavenged_large_blocks = 0;
stp->is_compacted = 0;
+ stp->bitmap = NULL;
}
}
generations[g].steps[s].to = &generations[g+1].steps[0];
}
- /* The oldest generation has one step. */
+ /* The oldest generation has one step and it is compacted. */
+ if (RtsFlags.GcFlags.compact) {
+ if (RtsFlags.GcFlags.generations == 1) {
+ belch("WARNING: compaction is incompatible with -G1; disabled");
+ } else {
+ oldest_gen->steps[0].is_compacted = 1;
+ }
+ }
oldest_gen->steps[0].to = &oldest_gen->steps[0];
/* generation 0 is special: that's the nursery */
*/
}
#else /* SMP */
- nursery_blocks = RtsFlags.GcFlags.minAllocAreaSize;
- g0s0->blocks = allocNursery(NULL, nursery_blocks);
- g0s0->n_blocks = nursery_blocks;
+ g0s0->blocks = allocNursery(NULL, RtsFlags.GcFlags.minAllocAreaSize);
+ g0s0->n_blocks = RtsFlags.GcFlags.minAllocAreaSize;
g0s0->to_blocks = NULL;
g0s0->n_to_blocks = 0;
- MainRegTable.rNursery = g0s0->blocks;
- MainRegTable.rCurrentNursery = g0s0->blocks;
+ MainCapability.r.rNursery = g0s0->blocks;
+ MainCapability.r.rCurrentNursery = g0s0->blocks;
/* hp, hpLim, hp_bd, to_space etc. aren't used in G0S0 */
#endif
}
}
#else
for (bd = g0s0->blocks; bd; bd = bd->link) {
+#ifdef PROFILING
+ // @LDV profiling
+ // Reset every word in the nursery to zero when doing LDV profiling.
+ // This relieves the mutator of the burden of zeroing every new closure,
+ // which is stored in the nursery.
+ //
+ // Todo: make it more efficient, e.g. memcpy()
+ //
+ StgPtr p;
+ if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_LDV) {
+ for (p = bd->start; p < bd->start + BLOCK_SIZE_W; p++)
+ *p = 0;
+ }
+#endif
bd->free = bd->start;
ASSERT(bd->gen_no == 0);
ASSERT(bd->step == g0s0);
IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
}
- MainRegTable.rNursery = g0s0->blocks;
- MainRegTable.rCurrentNursery = g0s0->blocks;
+ MainCapability.r.rNursery = g0s0->blocks;
+ MainCapability.r.rCurrentNursery = g0s0->blocks;
#endif
}
bdescr *
-allocNursery (bdescr *last_bd, nat blocks)
+allocNursery (bdescr *tail, nat blocks)
{
bdescr *bd;
nat i;
- /* Allocate a nursery */
+ // Allocate a nursery: we allocate fresh blocks one at a time and
+ // cons them on to the front of the list, not forgetting to update
+ // the back pointer on the tail of the list to point to the new block.
for (i=0; i < blocks; i++) {
+ // @LDV profiling
+ /*
+ processNursery() in LdvProfile.c assumes that every block group in
+ the nursery contains only a single block. So, if a block group is
+ given multiple blocks, change processNursery() accordingly.
+ */
bd = allocBlock();
- bd->link = last_bd;
+ bd->link = tail;
+ // double-link the nursery: we might need to insert blocks
+ if (tail != NULL) {
+ tail->u.back = bd;
+ }
bd->step = g0s0;
bd->gen_no = 0;
bd->flags = 0;
bd->free = bd->start;
- last_bd = bd;
+ tail = bd;
}
- return last_bd;
+ tail->u.back = NULL;
+ return tail;
}
void
resizeNursery ( nat blocks )
{
bdescr *bd;
+ nat nursery_blocks;
#ifdef SMP
barf("resizeNursery: can't resize in SMP mode");
#endif
+ nursery_blocks = g0s0->n_blocks;
if (nursery_blocks == blocks) {
- ASSERT(g0s0->n_blocks == blocks);
return;
}
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;
+
+ bd = g0s0->blocks;
+ while (nursery_blocks > blocks) {
+ next_bd = bd->link;
+ next_bd->u.back = NULL;
+ nursery_blocks -= bd->blocks; // might be a large block
+ freeGroup(bd);
+ bd = next_bd;
}
g0s0->blocks = bd;
+ // might have gone just under, by freeing a large block, so make
+ // up the difference.
+ if (nursery_blocks < blocks) {
+ g0s0->blocks = allocNursery(g0s0->blocks, blocks-nursery_blocks);
+ }
}
- g0s0->n_blocks = nursery_blocks = blocks;
+ g0s0->n_blocks = blocks;
+ ASSERT(countBlocks(g0s0->blocks) == g0s0->n_blocks);
}
/* -----------------------------------------------------------------------------
}
#else /* !SMP */
- bdescr *current_nursery = MainRegTable.rCurrentNursery;
+ bdescr *current_nursery = MainCapability.r.rCurrentNursery;
- allocated = (nursery_blocks * BLOCK_SIZE_W) + allocated_bytes();
+ allocated = (g0s0->n_blocks * BLOCK_SIZE_W) + allocated_bytes();
for ( bd = current_nursery->link; bd != NULL; bd = bd->link ) {
allocated -= BLOCK_SIZE_W;
}
for (bd = large_alloc_list; bd; bd = bd->link) {
total_blocks += bd->blocks;
}
-
+
+#ifdef PROFILING
+ if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_RETAINER) {
+ for (bd = firstStack; bd != NULL; bd = bd->link)
+ total_blocks += bd->blocks;
+ }
+#endif
+
+ // count the blocks allocated by the arena allocator
+ total_blocks += arenaBlocks();
+
/* count the blocks on the free list */
free_blocks = countFreeList();
ASSERT(total_blocks + free_blocks == mblocks_allocated * BLOCKS_PER_MBLOCK);
}
-static nat
+
+nat
countBlocks(bdescr *bd)
{
nat n;
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
for (s = 0; s < generations[g].n_steps; s++) {
- if (g == 0 && s == 0) { continue; }
- checkHeap(generations[g].steps[s].blocks);
- checkChain(generations[g].steps[s].large_objects);
ASSERT(countBlocks(generations[g].steps[s].blocks)
== generations[g].steps[s].n_blocks);
ASSERT(countBlocks(generations[g].steps[s].large_objects)
== generations[g].steps[s].n_large_blocks);
+ if (g == 0 && s == 0) { continue; }
+ checkHeap(generations[g].steps[s].blocks);
+ checkChain(generations[g].steps[s].large_objects);
if (g > 0) {
checkMutableList(generations[g].mut_list, g);
checkMutOnceList(generations[g].mut_once_list, g);