From 03f8b41b44fafe3788df84da2f5bf56334d4e8ae Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 8 Jun 2014 13:12:12 +0100 Subject: [PATCH] Encapsulate the artifical ageing and reclaiming that's need to ensure that all the memory in a segment is accounted as free. addresses point made by rb in Copied from Perforce Change: 186428 ServerID: perforce.ravenbrook.com --- mps/code/chain.h | 7 ++++--- mps/code/locus.c | 15 ++++++++++++--- mps/code/poolamc.c | 19 ++++++++----------- mps/code/poolams.c | 20 +++++++++++--------- mps/code/poolawl.c | 20 +++++++++++--------- mps/code/poollo.c | 22 ++++++++++------------ mps/design/strategy.txt | 9 +++++++-- 7 files changed, 63 insertions(+), 49 deletions(-) diff --git a/mps/code/chain.h b/mps/code/chain.h index bd2dd650dbe..87cfa08dd71 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -1,7 +1,7 @@ /* chain.h: GENERATION CHAINS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #ifndef chain_h @@ -90,7 +90,8 @@ extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool); extern void PoolGenFinish(PoolGen pgen); extern Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size, Bool withReservoirPermit, ArgList args); -extern void PoolGenFree(PoolGen pgen, Seg seg); +extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize, + Size newSize, Bool deferred); extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred); extern void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred); extern void PoolGenAccountForAge(PoolGen pgen, Size aged, Bool deferred); @@ -104,7 +105,7 @@ extern void PoolGenAccountForSegMerge(PoolGen pgen); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/locus.c b/mps/code/locus.c index d7fb4f038f6..537eea666e8 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -630,13 +630,15 @@ void PoolGenAccountForSegMerge(PoolGen pgen) /* PoolGenFree -- free a segment and update accounting * - * Call this when all the memory in the segment is accounted as free. - * (If not, call PoolGenAccountForAge and then PoolGenAccountForReclaim first.) + * Pass the amount of memory in the segment that is accounted as free, + * old, or new, respectively. The deferred flag is as for + * PoolGenAccountForFill. * * See */ -void PoolGenFree(PoolGen pgen, Seg seg) +void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize, + Size newSize, Bool deferred) { Size size; @@ -644,6 +646,13 @@ void PoolGenFree(PoolGen pgen, Seg seg) AVERT(Seg, seg); size = SegSize(seg); + AVER(freeSize + oldSize + newSize == size); + + /* Pretend to age and reclaim the contents of the segment to ensure + * that the entire segment is accounted as free. */ + PoolGenAccountForAge(pgen, newSize, deferred); + PoolGenAccountForReclaim(pgen, oldSize + newSize, deferred); + AVER(pgen->totalSize >= size); pgen->totalSize -= size; STATISTIC_STAT ({ diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1f2cad0314f..20c5a168cdd 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -953,13 +953,12 @@ static void AMCFinish(Pool pool) Seg seg = SegOfPoolRing(node); amcGen gen = amcSegGen(seg); amcSeg amcseg = Seg2amcSeg(seg); - - if (!amcseg->old) { - PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred); - amcseg->old = TRUE; - } - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), amcseg->deferred); - PoolGenFree(&gen->pgen, seg); + AVERT(amcSeg, amcseg); + PoolGenFree(&gen->pgen, seg, + 0, + amcseg->old ? SegSize(seg) : 0, + amcseg->old ? 0 : SegSize(seg), + amcseg->deferred); } /* Disassociate forwarding buffers from gens before they are */ @@ -2004,8 +2003,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) /* We may not free a buffered seg. */ AVER(SegBuffer(seg) == NULL); - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); - PoolGenFree(&gen->pgen, seg); + PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred); } else { /* Seg retained */ STATISTIC_STAT( { @@ -2083,8 +2081,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) trace->reclaimSize += SegSize(seg); - PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred); - PoolGenFree(&gen->pgen, seg); + PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred); } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index cd85651a4fe..b5e942c7e84 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -736,16 +736,14 @@ static void AMSSegsDestroy(AMS ams) RING_FOR(node, ring, next) { Seg seg = SegOfPoolRing(node); AMSSeg amsseg = Seg2AMSSeg(seg); + AVERT(AMSSeg, amsseg); AVER(amsseg->ams == ams); AMSSegFreeCheck(amsseg); - PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains), FALSE); - amsseg->oldGrains += amsseg->newGrains; - amsseg->newGrains = 0; - PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, amsseg->oldGrains), FALSE); - amsseg->freeGrains += amsseg->oldGrains; - amsseg->oldGrains = 0; - AVER(amsseg->freeGrains == amsseg->grains); - PoolGenFree(&ams->pgen, seg); + PoolGenFree(&ams->pgen, seg, + AMSGrainsSize(ams, amsseg->freeGrains), + AMSGrainsSize(ams, amsseg->oldGrains), + AMSGrainsSize(ams, amsseg->newGrains), + FALSE); } } @@ -1636,7 +1634,11 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) if (amsseg->freeGrains == grains && SegBuffer(seg) == NULL) /* No survivors */ - PoolGenFree(&ams->pgen, seg); + PoolGenFree(&ams->pgen, seg, + AMSGrainsSize(ams, amsseg->freeGrains), + AMSGrainsSize(ams, amsseg->oldGrains), + AMSGrainsSize(ams, amsseg->newGrains), + FALSE); } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index ffd95c15b4d..31af1dcd160 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -609,14 +609,12 @@ static void AWLFinish(Pool pool) RING_FOR(node, ring, nextNode) { Seg seg = SegOfPoolRing(node); AWLSeg awlseg = Seg2AWLSeg(seg); - PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains), FALSE); - awlseg->oldGrains += awlseg->newGrains; - awlseg->newGrains = 0; - PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, awlseg->oldGrains), FALSE); - awlseg->freeGrains += awlseg->oldGrains; - awlseg->oldGrains = 0; - AVER(awlseg->freeGrains == awlseg->grains); - PoolGenFree(&awl->pgen, seg); + AVERT(AWLSeg, awlseg); + PoolGenFree(&awl->pgen, seg, + AWLGrainsSize(awl, awlseg->freeGrains), + AWLGrainsSize(awl, awlseg->oldGrains), + AWLGrainsSize(awl, awlseg->newGrains), + FALSE); } awl->sig = SigInvalid; PoolGenFinish(&awl->pgen); @@ -1175,7 +1173,11 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg) if (awlseg->freeGrains == awlseg->grains && buffer == NULL) /* No survivors */ - PoolGenFree(&awl->pgen, seg); + PoolGenFree(&awl->pgen, seg, + AWLGrainsSize(awl, awlseg->freeGrains), + AWLGrainsSize(awl, awlseg->oldGrains), + AWLGrainsSize(awl, awlseg->newGrains), + FALSE); } diff --git a/mps/code/poollo.c b/mps/code/poollo.c index a75fc0b5ba3..af93c12bd13 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -391,7 +391,11 @@ static void loSegReclaim(LOSeg loseg, Trace trace) SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace)); if (!marked) - PoolGenFree(&lo->pgen, seg); + PoolGenFree(&lo->pgen, seg, + LOGrainsSize(lo, loseg->freeGrains), + LOGrainsSize(lo, loseg->oldGrains), + LOGrainsSize(lo, loseg->newGrains), + FALSE); } /* This walks over _all_ objects in the heap, whether they are */ @@ -536,18 +540,12 @@ static void LOFinish(Pool pool) RING_FOR(node, &pool->segRing, nextNode) { Seg seg = SegOfPoolRing(node); LOSeg loseg = SegLOSeg(seg); - AVERT(LOSeg, loseg); - UNUSED(loseg); /* */ - - PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains), FALSE); - loseg->oldGrains += loseg->newGrains; - loseg->newGrains = 0; - PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, loseg->oldGrains), FALSE); - loseg->freeGrains += loseg->oldGrains; - loseg->oldGrains = 0; - AVER(loseg->freeGrains == loSegGrains(loseg)); - PoolGenFree(&lo->pgen, seg); + PoolGenFree(&lo->pgen, seg, + LOGrainsSize(lo, loseg->freeGrains), + LOGrainsSize(lo, loseg->oldGrains), + LOGrainsSize(lo, loseg->newGrains), + FALSE); } PoolGenFinish(&lo->pgen); diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index 3ab1402d8dd..40b88863af9 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -270,8 +270,13 @@ _`.accounting.op`: The following operations are provided: _`.accounting.op.alloc`: Allocate a segment in a pool generation. Debit *total*, credit *free*. (But see `.account.total.negated`_.) -_`.accounting.op.free`: Free a segment. Debit *free*, credit *total*. -(But see `.account.total.negated`_.) +_`.accounting.op.free`: Free a segment. First, ensure that the +contents of the segment are accounted as free, by artificially ageing +any memory accounted as *new* or *newDeferred* (see +`.accounting.op.age`_) and then artifically reclaiming any memory +accounted as *old* or *oldDeferred* (see `.accounting.op.reclaim`_). +Finally, debit *free*, credit *total*. (But see +`.account.total.negated`_.) _`.accounting.op.fill`: Allocate memory, for example by filling a buffer. Debit *free*, credit *new* or *newDeferred*.