summaryrefslogtreecommitdiff
path: root/rts/sm/Storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/sm/Storage.c')
-rw-r--r--rts/sm/Storage.c178
1 files changed, 95 insertions, 83 deletions
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index 0ff37d2582..17798a25b8 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -1,6 +1,6 @@
/* -----------------------------------------------------------------------------
*
- * (c) The GHC Team, 1998-2008
+ * (c) The GHC Team, 1998-2012
*
* Storage manager front end
*
@@ -24,7 +24,7 @@
#include "Arena.h"
#include "Capability.h"
#include "Schedule.h"
-#include "RetainerProfile.h" // for counting memory blocks (memInventory)
+#include "RetainerProfile.h" // for counting memory blocks (memInventory)
#include "OSMem.h"
#include "Trace.h"
#include "GC.h"
@@ -46,8 +46,8 @@ nat large_alloc_lim; /* GC if n_large_blocks in any nursery
bdescr *exec_block;
-generation *generations = NULL; /* all the generations */
-generation *g0 = NULL; /* generation 0, for convenience */
+generation *generations = NULL; /* all the generations */
+generation *g0 = NULL; /* generation 0, for convenience */
generation *oldest_gen = NULL; /* oldest generation, for convenience */
nursery *nurseries = NULL; /* array of nurseries, size == n_capabilities */
@@ -92,7 +92,7 @@ initGeneration (generation *gen, int g)
}
void
-initStorage( void )
+initStorage (void)
{
nat g;
@@ -114,7 +114,7 @@ initStorage( void )
if (RtsFlags.GcFlags.maxHeapSize != 0 &&
RtsFlags.GcFlags.heapSizeSuggestion >
RtsFlags.GcFlags.maxHeapSize) {
- RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
+ RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
}
if (RtsFlags.GcFlags.maxHeapSize != 0 &&
@@ -134,8 +134,8 @@ initStorage( void )
/* allocate generation info array */
generations = (generation *)stgMallocBytes(RtsFlags.GcFlags.generations
- * sizeof(struct generation_),
- "initStorage: gens");
+ * sizeof(struct generation_),
+ "initStorage: gens");
/* Initialise all generations */
for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
@@ -155,9 +155,9 @@ initStorage( void )
/* The oldest generation has one step. */
if (RtsFlags.GcFlags.compact || RtsFlags.GcFlags.sweep) {
if (RtsFlags.GcFlags.generations == 1) {
- errorBelch("WARNING: compact/sweep is incompatible with -G1; disabled");
+ errorBelch("WARNING: compact/sweep is incompatible with -G1; disabled");
} else {
- oldest_gen->mark = 1;
+ oldest_gen->mark = 1;
if (RtsFlags.GcFlags.compact)
oldest_gen->compact = 1;
}
@@ -186,6 +186,13 @@ initStorage( void )
IF_DEBUG(gc, statDescribeGens());
RELEASE_SM_LOCK;
+
+ traceEventHeapInfo(CAPSET_HEAP_DEFAULT,
+ RtsFlags.GcFlags.generations,
+ RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE_W * sizeof(W_),
+ RtsFlags.GcFlags.minAllocAreaSize * BLOCK_SIZE_W * sizeof(W_),
+ MBLOCK_SIZE_W * sizeof(W_),
+ BLOCK_SIZE_W * sizeof(W_));
}
void storageAddCapabilities (nat from, nat to)
@@ -197,7 +204,7 @@ void storageAddCapabilities (nat from, nat to)
"storageAddCapabilities");
} else {
nurseries = stgMallocBytes(to * sizeof(struct nursery_),
- "storageAddCapabilities");
+ "storageAddCapabilities");
}
// we've moved the nurseries, so we have to update the rNursery
@@ -228,7 +235,8 @@ void storageAddCapabilities (nat from, nat to)
void
exitStorage (void)
{
- stat_exit(calcAllocated(rtsTrue));
+ lnat allocated = updateNurseriesStats();
+ stat_exit(allocated);
}
void
@@ -271,7 +279,7 @@ freeStorage (rtsBool free_heap)
- it puts the CAF on the oldest generation's mutable list.
This is so that we treat the CAF as a root when collecting
- younger generations.
+ younger generations.
------------------
Note [atomic CAF entry]
@@ -470,7 +478,7 @@ assignNurseriesToCapabilities (nat from, nat to)
for (i = from; i < to; i++) {
capabilities[i].r.rCurrentNursery = nurseries[i].blocks;
- capabilities[i].r.rCurrentAlloc = NULL;
+ capabilities[i].r.rCurrentAlloc = NULL;
}
}
@@ -482,7 +490,7 @@ allocNurseries (nat from, nat to)
for (i = from; i < to; i++) {
nurseries[i].blocks =
allocNursery(NULL, RtsFlags.GcFlags.minAllocAreaSize);
- nurseries[i].n_blocks =
+ nurseries[i].n_blocks =
RtsFlags.GcFlags.minAllocAreaSize;
}
assignNurseriesToCapabilities(from, to);
@@ -496,13 +504,14 @@ clearNurseries (void)
bdescr *bd;
for (i = 0; i < n_capabilities; i++) {
- for (bd = nurseries[i].blocks; bd; bd = bd->link) {
- allocated += (lnat)(bd->free - bd->start);
+ for (bd = nurseries[i].blocks; bd; bd = bd->link) {
+ allocated += (lnat)(bd->free - bd->start);
+ capabilities[i].total_allocated += (lnat)(bd->free - bd->start);
bd->free = bd->start;
- ASSERT(bd->gen_no == 0);
- ASSERT(bd->gen == g0);
- IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
- }
+ ASSERT(bd->gen_no == 0);
+ ASSERT(bd->gen == g0);
+ IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
+ }
}
return allocated;
@@ -521,13 +530,13 @@ countNurseryBlocks (void)
lnat blocks = 0;
for (i = 0; i < n_capabilities; i++) {
- blocks += nurseries[i].n_blocks;
+ blocks += nurseries[i].n_blocks;
}
return blocks;
}
static void
-resizeNursery ( nursery *nursery, nat blocks )
+resizeNursery (nursery *nursery, nat blocks)
{
bdescr *bd;
nat nursery_blocks;
@@ -537,28 +546,28 @@ resizeNursery ( nursery *nursery, nat blocks )
if (nursery_blocks < blocks) {
debugTrace(DEBUG_gc, "increasing size of nursery to %d blocks",
- blocks);
+ blocks);
nursery->blocks = allocNursery(nursery->blocks, blocks-nursery_blocks);
}
else {
bdescr *next_bd;
debugTrace(DEBUG_gc, "decreasing size of nursery to %d blocks",
- blocks);
+ blocks);
bd = nursery->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;
+ next_bd = bd->link;
+ next_bd->u.back = NULL;
+ nursery_blocks -= bd->blocks; // might be a large block
+ freeGroup(bd);
+ bd = next_bd;
}
nursery->blocks = bd;
// might have gone just under, by freeing a large block, so make
// up the difference.
if (nursery_blocks < blocks) {
- nursery->blocks = allocNursery(nursery->blocks, blocks-nursery_blocks);
+ nursery->blocks = allocNursery(nursery->blocks, blocks-nursery_blocks);
}
}
@@ -574,7 +583,7 @@ resizeNurseriesFixed (nat blocks)
{
nat i;
for (i = 0; i < n_capabilities; i++) {
- resizeNursery(&nurseries[i], blocks);
+ resizeNursery(&nurseries[i], blocks);
}
}
@@ -628,7 +637,7 @@ allocate (Capability *cap, lnat n)
CCS_ALLOC(cap->r.rCCCS,n);
if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
- lnat req_blocks = (lnat)BLOCK_ROUND_UP(n*sizeof(W_)) / BLOCK_SIZE;
+ lnat req_blocks = (lnat)BLOCK_ROUND_UP(n*sizeof(W_)) / BLOCK_SIZE;
// Attempting to allocate an object larger than maxHeapSize
// should definitely be disallowed. (bug #1791)
@@ -644,19 +653,20 @@ allocate (Capability *cap, lnat n)
// Allocating the memory would be bad, because the user
// has requested that we not exceed maxHeapSize, so we
// just exit.
- stg_exit(EXIT_HEAPOVERFLOW);
+ stg_exit(EXIT_HEAPOVERFLOW);
}
ACQUIRE_SM_LOCK
- bd = allocGroup(req_blocks);
- dbl_link_onto(bd, &g0->large_objects);
- g0->n_large_blocks += bd->blocks; // might be larger than req_blocks
+ bd = allocGroup(req_blocks);
+ dbl_link_onto(bd, &g0->large_objects);
+ g0->n_large_blocks += bd->blocks; // might be larger than req_blocks
g0->n_new_large_words += n;
RELEASE_SM_LOCK;
initBdescr(bd, g0, g0);
- bd->flags = BF_LARGE;
- bd->free = bd->start + n;
- return bd->start;
+ bd->flags = BF_LARGE;
+ bd->free = bd->start + n;
+ cap->total_allocated += n;
+ return bd->start;
}
/* small allocation (<LARGE_OBJECT_THRESHOLD) */
@@ -733,7 +743,7 @@ allocatePinned (Capability *cap, lnat n)
// If the request is for a large object, then allocate()
// will give us a pinned object anyway.
if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
- p = allocate(cap, n);
+ p = allocate(cap, n);
Bdescr(p)->flags |= BF_PINNED;
return p;
}
@@ -786,7 +796,7 @@ allocatePinned (Capability *cap, lnat n)
if (bd->link != NULL) {
bd->link->u.back = cap->r.rCurrentNursery;
}
- cap->r.rNursery->n_blocks--;
+ cap->r.rNursery->n_blocks -= bd->blocks;
}
cap->pinned_object_block = bd;
@@ -827,7 +837,7 @@ dirty_MUT_VAR(StgRegTable *reg, StgClosure *p)
{
Capability *cap = regTableToCapability(reg);
if (p->header.info == &stg_MUT_VAR_CLEAN_info) {
- p->header.info = &stg_MUT_VAR_DIRTY_info;
+ p->header.info = &stg_MUT_VAR_DIRTY_info;
recordClosureMutated(cap,p);
}
}
@@ -895,34 +905,36 @@ dirty_MVAR(StgRegTable *reg, StgClosure *p)
* -------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
- * calcAllocated()
+ * updateNurseriesStats()
*
- * Approximate how much we've allocated: number of blocks in the
- * nursery + blocks allocated via allocate() - unused nusery blocks.
- * This leaves a little slop at the end of each block.
+ * Update the per-cap total_allocated numbers with an approximation of
+ * the amount of memory used in each cap's nursery. Also return the
+ * total across all caps.
+ *
+ * Since this update is also performed by clearNurseries() then we only
+ * need this function for the final stats when the RTS is shutting down.
* -------------------------------------------------------------------------- */
lnat
-calcAllocated (rtsBool include_nurseries)
+updateNurseriesStats (void)
{
- nat allocated = 0;
- nat i;
-
- // When called from GC.c, we already have the allocation count for
- // the nursery from resetNurseries(), so we don't need to walk
- // through these block lists again.
- if (include_nurseries)
- {
- for (i = 0; i < n_capabilities; i++) {
- allocated += countOccupied(nurseries[i].blocks);
- }
- }
+ lnat allocated = 0;
+ nat i;
- // add in sizes of new large and pinned objects
- allocated += g0->n_new_large_words;
+ for (i = 0; i < n_capabilities; i++) {
+ int cap_allocated = countOccupied(nurseries[i].blocks);
+ capabilities[i].total_allocated += cap_allocated;
+ allocated += cap_allocated;
+ }
+
+ return allocated;
+}
- return allocated;
-}
+lnat
+countLargeAllocated (void)
+{
+ return g0->n_new_large_words;
+}
lnat countOccupied (bdescr *bd)
{
@@ -1095,24 +1107,24 @@ void *allocateExec (nat bytes, void **exec_ret)
n = (bytes + sizeof(W_) + 1) / sizeof(W_);
if (n+1 > BLOCK_SIZE_W) {
- barf("allocateExec: can't handle large objects");
+ barf("allocateExec: can't handle large objects");
}
if (exec_block == NULL ||
- exec_block->free + n + 1 > exec_block->start + BLOCK_SIZE_W) {
- bdescr *bd;
- lnat pagesize = getPageSize();
- bd = allocGroup(stg_max(1, pagesize / BLOCK_SIZE));
- debugTrace(DEBUG_gc, "allocate exec block %p", bd->start);
- bd->gen_no = 0;
- bd->flags = BF_EXEC;
- bd->link = exec_block;
- if (exec_block != NULL) {
- exec_block->u.back = bd;
- }
- bd->u.back = NULL;
- setExecutable(bd->start, bd->blocks * BLOCK_SIZE, rtsTrue);
- exec_block = bd;
+ exec_block->free + n + 1 > exec_block->start + BLOCK_SIZE_W) {
+ bdescr *bd;
+ lnat pagesize = getPageSize();
+ bd = allocGroup(stg_max(1, pagesize / BLOCK_SIZE));
+ debugTrace(DEBUG_gc, "allocate exec block %p", bd->start);
+ bd->gen_no = 0;
+ bd->flags = BF_EXEC;
+ bd->link = exec_block;
+ if (exec_block != NULL) {
+ exec_block->u.back = bd;
+ }
+ bd->u.back = NULL;
+ setExecutable(bd->start, bd->blocks * BLOCK_SIZE, rtsTrue);
+ exec_block = bd;
}
*(exec_block->free) = n; // store the size of this chunk
exec_block->gen_no += n; // gen_no stores the number of words allocated
@@ -1130,11 +1142,11 @@ void freeExec (void *addr)
bdescr *bd = Bdescr((StgPtr)p);
if ((bd->flags & BF_EXEC) == 0) {
- barf("freeExec: not executable");
+ barf("freeExec: not executable");
}
if (*(StgPtr)p == 0) {
- barf("freeExec: already free?");
+ barf("freeExec: already free?");
}
ACQUIRE_SM_LOCK;
@@ -1163,10 +1175,10 @@ void freeExec (void *addr)
#ifdef DEBUG
// handy function for use in gdb, because Bdescr() is inlined.
-extern bdescr *_bdescr( StgPtr p );
+extern bdescr *_bdescr (StgPtr p);
bdescr *
-_bdescr( StgPtr p )
+_bdescr (StgPtr p)
{
return Bdescr(p);
}