diff --git a/mps/code/apss.c b/mps/code/apss.c index 81edbe7d04d..cdf88cee43f 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -41,9 +41,21 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) } +/* check_allocated_size -- check the allocated size of the pool */ + +static void check_allocated_size(mps_pool_t pool, mps_ap_t ap, size_t allocated) +{ + size_t total = mps_pool_total_size(pool); + size_t free = mps_pool_free_size(pool); + size_t ap_free = (size_t)((char *)ap->limit - (char *)ap->init); + Insist(total - free == allocated + ap_free); +} + + /* stress -- create a pool of the requested type and allocate in it */ -static mps_res_t stress(mps_arena_t arena, mps_align_t align, +static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, + mps_align_t align, size_t (*size)(size_t i, mps_align_t align), const char *name, mps_class_t class, mps_arg_s args[]) { @@ -53,6 +65,8 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, size_t i, k; int *ps[testSetSIZE]; size_t ss[testSetSIZE]; + size_t allocated = 0; /* Total allocated memory */ + size_t debugOverhead = options ? 2 * alignUp(options->fence_size, align) : 0; printf("stress %s\n", name); @@ -66,8 +80,10 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, res = make((mps_addr_t *)&ps[i], ap, ss[i]); if (res != MPS_RES_OK) goto allocFail; + allocated += ss[i] + debugOverhead; if (ss[i] >= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ + check_allocated_size(pool, ap, allocated); } mps_pool_check_fenceposts(pool); @@ -90,6 +106,8 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, mps_free(pool, (mps_addr_t)ps[i], ss[i]); /* if (i == testSetSIZE/2) */ /* PoolDescribe((Pool)pool, mps_lib_stdout); */ + Insist(ss[i] + debugOverhead <= allocated); + allocated -= ss[i] + debugOverhead; } /* allocate some new objects */ for (i=testSetSIZE/2; iclass->name, name); mps_arena_park(arena); /* make some trees */ @@ -167,7 +169,6 @@ static void test_trees(int mode, const char *name, mps_arena_t arena, (*reg)((mps_word_t)root[i], arena); } - printf("Losing all pointers to the trees.\n"); /* clean out the roots */ for(i = 0; i < rootCOUNT; ++i) { root[i] = 0; @@ -190,9 +191,15 @@ static void test_trees(int mode, const char *name, mps_arena_t arena, object_alloc = 0; while (object_alloc < 1000 && !mps_message_poll(arena)) (void)DYLAN_INT(object_alloc++); + printf(" Done.\n"); break; } ++ collections; + { + size_t live_size = (object_count - finals) * sizeof(void *) * 3; + size_t alloc_size = mps_pool_total_size(pool) - mps_pool_free_size(pool); + Insist(live_size <= alloc_size); + } while (mps_message_poll(arena)) { mps_message_t message; mps_addr_t objaddr; @@ -238,9 +245,9 @@ static void test_pool(int mode, mps_arena_t arena, mps_chain_t chain, "root_create\n"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n"); - test_trees(mode, "numbered", arena, ap, make_numbered_tree, + test_trees(mode, "numbered", arena, pool, ap, make_numbered_tree, register_numbered_tree); - test_trees(mode, "indirect", arena, ap, make_indirect_tree, + test_trees(mode, "indirect", arena, pool, ap, make_indirect_tree, register_indirect_tree); mps_ap_destroy(ap); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index e141edb2bc5..533d99e462f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -222,6 +222,9 @@ extern Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr); extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, void *v, size_t s); extern void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); +extern Size PoolTotalSize(Pool pool); +extern Size PoolFreeSize(Pool pool); + extern Res PoolTrivInit(Pool pool, ArgList arg); extern void PoolTrivFinish(Pool pool); extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size, @@ -275,6 +278,7 @@ extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsStepMethod step, extern void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); extern PoolDebugMixin PoolNoDebugMixin(Pool pool); extern BufferClass PoolNoBufferClass(void); +extern Size PoolNoSize(Pool pool); #define ClassOfPool(pool) ((pool)->class) #define SuperclassOfPool(pool) \ diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index a2019bca0f5..6c61b6a9ad8 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -23,9 +23,20 @@ #define testLOOPS 10 +/* check_allocated_size -- check the allocated size of the pool */ + +static void check_allocated_size(mps_pool_t pool, size_t allocated) +{ + size_t total = mps_pool_total_size(pool); + size_t free = mps_pool_free_size(pool); + Insist(total - free == allocated); +} + + /* stress -- create a pool of the requested type and allocate in it */ -static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i), +static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, + size_t (*size)(size_t i), mps_align_t align, const char *name, mps_class_t pool_class, mps_arg_s *args) { @@ -34,8 +45,10 @@ static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i), size_t i, k; int *ps[testSetSIZE]; size_t ss[testSetSIZE]; + size_t allocated = 0; /* Total allocated memory */ + size_t debugOverhead = options ? 2 * alignUp(options->fence_size, align) : 0; - printf("%s\n", name); + printf("Pool class %s, alignment %u\n", name, (unsigned)align); res = mps_pool_create_k(&pool, arena, pool_class, args); if (res != MPS_RES_OK) @@ -48,8 +61,10 @@ static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i), res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]); if (res != MPS_RES_OK) return res; + allocated += alignUp(ss[i], align) + debugOverhead; if (ss[i] >= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ + check_allocated_size(pool, allocated); } mps_pool_check_fenceposts(pool); @@ -72,13 +87,17 @@ static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i), mps_free(pool, (mps_addr_t)ps[i], ss[i]); /* if (i == testSetSIZE/2) */ /* PoolDescribe((Pool)pool, mps_lib_stdout); */ + Insist(alignUp(ss[i], align) + debugOverhead <= allocated); + allocated -= alignUp(ss[i], align) + debugOverhead; } /* allocate some new objects */ for (i=testSetSIZE/2; i */ } MFSStruct; @@ -158,7 +162,7 @@ typedef struct MVStruct { /* MV pool outer structure */ Size extendBy; /* segment size to extend pool by */ Size avgSize; /* client estimate of allocation size */ Size maxSize; /* client estimate of maximum size */ - Size space; /* total free space in pool */ + Size free; /* free space in pool */ Size lost; /* */ RingStruct spans; /* span chain */ Sig sig; /* */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 04f73a7e42d..8bee48e202e 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -237,6 +237,7 @@ typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p); typedef BufferClass (*PoolBufferClassMethod)(void); typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream); typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool); +typedef Size (*PoolSizeMethod)(Pool pool); /* Messages diff --git a/mps/code/mps.h b/mps/code/mps.h index f927ea48b30..46b9e8d81dc 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -472,6 +472,11 @@ extern mps_res_t mps_pool_create_v(mps_pool_t *, mps_arena_t, extern mps_res_t mps_pool_create_k(mps_pool_t *, mps_arena_t, mps_class_t, mps_arg_s []); extern void mps_pool_destroy(mps_pool_t); +extern size_t mps_pool_total_size(mps_pool_t); +extern size_t mps_pool_free_size(mps_pool_t); + + +/* Chains */ /* .gen-param: This structure must match . */ typedef struct mps_gen_param_s { @@ -483,6 +488,9 @@ extern mps_res_t mps_chain_create(mps_chain_t *, mps_arena_t, size_t, mps_gen_param_s *); extern void mps_chain_destroy(mps_chain_t); + +/* Manual Allocation */ + extern mps_res_t mps_alloc(mps_addr_t *, mps_pool_t, size_t); extern mps_res_t mps_alloc_v(mps_addr_t *, mps_pool_t, size_t, va_list); extern void mps_free(mps_pool_t, mps_addr_t, size_t); diff --git a/mps/code/mpscmv.h b/mps/code/mpscmv.h index 805db19b8af..aeb163aec4a 100644 --- a/mps/code/mpscmv.h +++ b/mps/code/mpscmv.h @@ -9,8 +9,8 @@ #include "mps.h" -extern size_t mps_mv_free_size(mps_pool_t mps_pool); -extern size_t mps_mv_size(mps_pool_t mps_pool); +#define mps_mv_free_size(pool) (mps_pool_free_size(pool)) +#define mps_mv_size(pool) (mps_pool_total_size(pool)) extern mps_class_t mps_class_mv(void); extern mps_class_t mps_class_mv_debug(void); diff --git a/mps/code/mpscmvff.h b/mps/code/mpscmvff.h index f8bc97b7f3b..ec1eb22eff9 100644 --- a/mps/code/mpscmvff.h +++ b/mps/code/mpscmvff.h @@ -19,8 +19,8 @@ extern const struct mps_key_s _mps_key_mvff_first_fit; #define MPS_KEY_MVFF_FIRST_FIT (&_mps_key_mvff_first_fit) #define MPS_KEY_MVFF_FIRST_FIT_FIELD b -extern size_t mps_mvff_free_size(mps_pool_t mps_pool); -extern size_t mps_mvff_size(mps_pool_t mps_pool); +#define mps_mvff_free_size(pool) (mps_pool_free_size(pool)) +#define mps_mvff_size(pool) (mps_pool_total_size(pool)) extern mps_class_t mps_class_mvff(void); extern mps_class_t mps_class_mvff_debug(void); diff --git a/mps/code/mpscmvt.h b/mps/code/mpscmvt.h index f46e43267df..82792eb3f55 100644 --- a/mps/code/mpscmvt.h +++ b/mps/code/mpscmvt.h @@ -34,10 +34,12 @@ extern const struct mps_key_s _mps_key_mvt_frag_limit; */ extern mps_class_t mps_class_mvt(void); -/* The mvt pool class supports two extensions to the pool protocol: - size and free_size. */ -extern size_t mps_mvt_free_size(mps_pool_t mps_pool); -extern size_t mps_mvt_size(mps_pool_t mps_pool); +/* The mvt pool class formerly supported two extensions to the pool + protocol: size and free_size. These are deprecated in favour of the + generic pool function. */ + +#define mps_mvt_free_size(pool) (mps_pool_free_size(pool)) +#define mps_mvt_size(pool) (mps_pool_total_size(pool)) #endif /* mpscmvt_h */ diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 0573a6d4256..a679955456d 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -678,6 +678,40 @@ void mps_pool_destroy(mps_pool_t pool) ArenaLeave(arena); } +size_t mps_pool_total_size(mps_pool_t pool) +{ + Arena arena; + Size size; + + AVER(TESTT(Pool, pool)); + arena = PoolArena(pool); + + ArenaEnter(arena); + + size = PoolTotalSize(pool); + + ArenaLeave(arena); + + return (size_t)size; +} + +size_t mps_pool_free_size(mps_pool_t pool) +{ + Arena arena; + Size size; + + AVER(TESTT(Pool, pool)); + arena = PoolArena(pool); + + ArenaEnter(arena); + + size = PoolFreeSize(pool); + + ArenaLeave(arena); + + return (size_t)size; +} + mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size) { diff --git a/mps/code/pool.c b/mps/code/pool.c index 8bfa5d87a0c..bda9faea9b0 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -72,6 +72,8 @@ Bool PoolClassCheck(PoolClass class) CHECKL(FUNCHECK(class->bufferClass)); CHECKL(FUNCHECK(class->describe)); CHECKL(FUNCHECK(class->debugMixin)); + CHECKL(FUNCHECK(class->totalSize)); + CHECKL(FUNCHECK(class->freeSize)); CHECKS(PoolClass, class); return TRUE; } @@ -521,6 +523,26 @@ void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p) } +/* PoolTotalSize -- return total memory allocated from arena */ + +Size PoolTotalSize(Pool pool) +{ + AVERT(Pool, pool); + + return (*pool->class->totalSize)(pool); +} + + +/* PoolFreeSize -- return free memory (unused by client program) */ + +Size PoolFreeSize(Pool pool) +{ + AVERT(Pool, pool); + + return (*pool->class->freeSize)(pool); +} + + /* PoolDescribe -- describe a pool */ Res PoolDescribe(Pool pool, mps_lib_FILE *stream) diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index aa2ee5adcbd..62b25498ecd 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -160,6 +160,8 @@ DEFINE_CLASS(AbstractPoolClass, class) class->bufferClass = PoolNoBufferClass; class->describe = PoolTrivDescribe; class->debugMixin = PoolNoDebugMixin; + class->totalSize = PoolNoSize; + class->freeSize = PoolNoSize; class->labelled = FALSE; class->sig = PoolClassSig; } @@ -696,6 +698,14 @@ BufferClass PoolNoBufferClass(void) } +Size PoolNoSize(Pool pool) +{ + AVERT(Pool, pool); + NOTREACHED; + return 0; +} + + /* C. COPYRIGHT AND LICENSE * * Copyright (C) 2001-2014 Ravenbrook Limited . diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 92239f6e369..fa29f4a97fb 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -2266,6 +2266,50 @@ static Res AMCAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr) } +/* AMCTotalSize -- total memory allocated from the arena */ + +static Size AMCTotalSize(Pool pool) +{ + AMC amc; + Size size = 0; + Ring node, nextNode; + + AVERT(Pool, pool); + amc = Pool2AMC(pool); + AVERT(AMC, amc); + + RING_FOR(node, &amc->genRing, nextNode) { + amcGen gen = RING_ELT(amcGen, amcRing, node); + AVERT(amcGen, gen); + size += gen->pgen.totalSize; + } + + return size; +} + + +/* AMCFreeSize -- free memory (unused by client program) */ + +static Size AMCFreeSize(Pool pool) +{ + AMC amc; + Size size = 0; + Ring node, nextNode; + + AVERT(Pool, pool); + amc = Pool2AMC(pool); + AVERT(AMC, amc); + + RING_FOR(node, &amc->genRing, nextNode) { + amcGen gen = RING_ELT(amcGen, amcRing, node); + AVERT(amcGen, gen); + size += gen->pgen.freeSize; + } + + return size; +} + + /* AMCDescribe -- describe the contents of the AMC pool * * See . @@ -2365,6 +2409,8 @@ DEFINE_POOL_CLASS(AMCZPoolClass, this) this->addrObject = AMCAddrObject; this->walk = AMCWalk; this->bufferClass = amcBufClassGet; + this->totalSize = AMCTotalSize; + this->freeSize = AMCFreeSize; this->describe = AMCDescribe; AVERT(PoolClass, this); } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index e6c4e7d4837..71cbaef0733 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1658,6 +1658,34 @@ static void AMSFreeWalk(Pool pool, FreeBlockStepMethod f, void *p) } +/* AMSTotalSize -- total memory allocated from the arena */ + +static Size AMSTotalSize(Pool pool) +{ + AMS ams; + + AVERT(Pool, pool); + ams = Pool2AMS(pool); + AVERT(AMS, ams); + + return ams->pgen.totalSize; +} + + +/* AMSFreeSize -- free memory (unused by client program) */ + +static Size AMSFreeSize(Pool pool) +{ + AMS ams; + + AVERT(Pool, pool); + ams = Pool2AMS(pool); + AVERT(AMS, ams); + + return ams->pgen.freeSize; +} + + /* AMSDescribe -- the pool class description method * * Iterates over the segments, describing all of them. @@ -1729,6 +1757,8 @@ DEFINE_CLASS(AMSPoolClass, this) this->reclaim = AMSReclaim; this->walk = PoolNoWalk; /* TODO: job003738 */ this->freewalk = AMSFreeWalk; + this->totalSize = AMSTotalSize; + this->freeSize = AMSFreeSize; this->describe = AMSDescribe; AVERT(PoolClass, this); } diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 775d29d2018..1d6a6c31bd9 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1281,6 +1281,34 @@ static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, } +/* AWLTotalSize -- total memory allocated from the arena */ + +static Size AWLTotalSize(Pool pool) +{ + AWL awl; + + AVERT(Pool, pool); + awl = Pool2AWL(pool); + AVERT(AWL, awl); + + return awl->pgen.totalSize; +} + + +/* AWLFreeSize -- free memory (unused by client program) */ + +static Size AWLFreeSize(Pool pool) +{ + AWL awl; + + AVERT(Pool, pool); + awl = Pool2AWL(pool); + AVERT(AWL, awl); + + return awl->pgen.freeSize; +} + + /* AWLPoolClass -- the class definition */ DEFINE_POOL_CLASS(AWLPoolClass, this) @@ -1305,6 +1333,8 @@ DEFINE_POOL_CLASS(AWLPoolClass, this) this->fixEmergency = AWLFix; this->reclaim = AWLReclaim; this->walk = AWLWalk; + this->totalSize = AWLTotalSize; + this->freeSize = AWLFreeSize; AVERT(PoolClass, this); } diff --git a/mps/code/poollo.c b/mps/code/poollo.c index 06d3e68160f..c2b562df421 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -797,6 +797,34 @@ static void LOReclaim(Pool pool, Trace trace, Seg seg) } +/* LOTotalSize -- total memory allocated from the arena */ + +static Size LOTotalSize(Pool pool) +{ + LO lo; + + AVERT(Pool, pool); + lo = PoolPoolLO(pool); + AVERT(LO, lo); + + return lo->pgen.totalSize; +} + + +/* LOFreeSize -- free memory (unused by client program) */ + +static Size LOFreeSize(Pool pool) +{ + LO lo; + + AVERT(Pool, pool); + lo = PoolPoolLO(pool); + AVERT(LO, lo); + + return lo->pgen.freeSize; +} + + /* LOPoolClass -- the class definition */ DEFINE_POOL_CLASS(LOPoolClass, this) @@ -817,6 +845,8 @@ DEFINE_POOL_CLASS(LOPoolClass, this) this->fixEmergency = LOFix; this->reclaim = LOReclaim; this->walk = LOWalk; + this->totalSize = LOTotalSize; + this->freeSize = LOFreeSize; AVERT(PoolClass, this); } diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index b40094d839c..6ab9fd8f08f 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -123,6 +123,8 @@ static Res MFSInit(Pool pool, ArgList args) mfs->unitSize = unitSize; mfs->freeList = NULL; mfs->tractList = NULL; + mfs->total = 0; + mfs->free = 0; mfs->sig = MFSSig; AVERT(MFS, mfs); @@ -197,6 +199,10 @@ void MFSExtend(Pool pool, Addr base, Size size) TractSetP(tract, (void *)mfs->tractList); mfs->tractList = tract; + /* Update accounting */ + mfs->total += size; + mfs->free += size; + /* Sew together all the new empty units in the region, working down */ /* from the top so that they are in ascending order of address on the */ /* free list. */ @@ -270,6 +276,7 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size, /* Detach the first free unit from the free list and return its address. */ mfs->freeList = f->next; + mfs->free -= mfs->unitSize; *pReturn = (Addr)f; return ResOK; @@ -298,6 +305,35 @@ static void MFSFree(Pool pool, Addr old, Size size) h = (Header)old; h->next = mfs->freeList; mfs->freeList = h; + mfs->free += mfs->unitSize; +} + + +/* MFSTotalSize -- total memory allocated from the arena */ + +static Size MFSTotalSize(Pool pool) +{ + MFS mfs; + + AVERT(Pool, pool); + mfs = PoolPoolMFS(pool); + AVERT(MFS, mfs); + + return mfs->total; +} + + +/* MFSFreeSize -- free memory (unused by client program) */ + +static Size MFSFreeSize(Pool pool) +{ + MFS mfs; + + AVERT(Pool, pool); + mfs = PoolPoolMFS(pool); + AVERT(MFS, mfs); + + return mfs->free; } @@ -336,6 +372,8 @@ DEFINE_POOL_CLASS(MFSPoolClass, this) this->finish = MFSFinish; this->alloc = MFSAlloc; this->free = MFSFree; + this->totalSize = MFSTotalSize; + this->freeSize = MFSFreeSize; this->describe = MFSDescribe; AVERT(PoolClass, this); } @@ -370,6 +408,8 @@ Bool MFSCheck(MFS mfs) if(mfs->tractList != NULL) { CHECKD_NOSIG(Tract, mfs->tractList); } + CHECKL(mfs->free <= mfs->total); + CHECKL((mfs->total - mfs->free) % mfs->unitSize == 0); return TRUE; } diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 5c9dc98c6b6..5fac5a17478 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -116,7 +116,7 @@ typedef struct MVSpanStruct { MVBlockStruct base; /* sentinel at base of span */ MVBlockStruct limit; /* sentinel at limit of span */ MVBlock blocks; /* allocated blocks */ - Size space; /* total free space in span */ + Size free; /* free space in span */ Size largest; /* .design.largest */ Bool largestKnown; /* .design.largest */ unsigned blockCount; /* number of blocks on chain */ @@ -160,11 +160,11 @@ static Bool MVSpanCheck(MVSpan span) /* The sentinels mustn't overlap. */ CHECKL(span->base.limit <= span->limit.base); /* The free space can't be more than the gap between the sentinels. */ - CHECKL(span->space <= SpanInsideSentinels(span)); + CHECKL(span->free <= SpanInsideSentinels(span)); CHECKL(BoolCheck(span->largestKnown)); if (span->largestKnown) { /* .design.largest */ - CHECKL(span->largest <= span->space); + CHECKL(span->largest <= span->free); /* at least this much is free */ } else { CHECKL(span->largest == SpanSize(span)+1); @@ -277,7 +277,7 @@ static Res MVInit(Pool pool, ArgList args) mv->maxSize = maxSize; RingInit(&mv->spans); - mv->space = 0; + mv->free = 0; mv->lost = 0; mv->sig = MVSig; @@ -368,7 +368,7 @@ static Bool MVSpanAlloc(Addr *addrReturn, MVSpan span, Size size, span->largest = SpanSize(span) + 1; /* .design.largest */ } - span->space -= size; + span->free -= size; *addrReturn = new; return TRUE; } @@ -484,7 +484,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool) AVERT(MVBlock, block); - span->space += AddrOffset(base, limit); + span->free += AddrOffset(base, limit); if (freeAreaSize > span->largest) { /* .design.largest */ AVER(span->largestKnown); @@ -528,16 +528,16 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size, size = SizeAlignUp(size, pool->alignment); - if(size <= mv->space) { + if(size <= mv->free) { spans = &mv->spans; RING_FOR(node, spans, nextNode) { span = RING_ELT(MVSpan, spans, node); if((size <= span->largest) && /* .design.largest.alloc */ - (size <= span->space)) { + (size <= span->free)) { Addr new; if(MVSpanAlloc(&new, span, size, mvBlockPool(mv))) { - mv->space -= size; + mv->free -= size; AVER(AddrIsAligned(new, pool->alignment)); *pReturn = new; return ResOK; @@ -593,20 +593,20 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size, RingInit(&span->spans); span->base.base = span->base.limit = base; span->limit.base = span->limit.limit = limit; - span->space = AddrOffset(span->base.limit, span->limit.base); + span->free = AddrOffset(span->base.limit, span->limit.base); span->limit.next = NULL; span->base.next = &span->limit; span->blocks = &span->base; span->blockCount = 2; span->base.limit = AddrAdd(span->base.limit, size); - span->space -= size; - span->largest = span->space; + span->free -= size; + span->largest = span->free; span->largestKnown = TRUE; span->sig = MVSpanSig; AVERT(MVSpan, span); - mv->space += span->space; + mv->free += span->free; RingInsert(&mv->spans, &span->spans); /* use RingInsert so that we examine this new span first when allocating */ @@ -655,16 +655,16 @@ static void MVFree(Pool pool, Addr old, Size size) if(res != ResOK) mv->lost += size; else - mv->space += size; + mv->free += size; /* free space should be less than total space */ - AVER(span->space <= SpanInsideSentinels(span)); - if(span->space == SpanSize(span)) { /* the whole span is free */ + AVER(span->free <= SpanInsideSentinels(span)); + if(span->free == SpanSize(span)) { /* the whole span is free */ AVER(span->blockCount == 2); /* both blocks are the trivial sentinel blocks */ AVER(span->base.limit == span->base.base); AVER(span->limit.limit == span->limit.base); - mv->space -= span->space; + mv->free -= span->free; ArenaFree(TractBase(span->tract), span->size, pool); RingRemove(&span->spans); RingFinish(&span->spans); @@ -687,6 +687,51 @@ static PoolDebugMixin MVDebugMixin(Pool pool) } +/* MVTotalSize -- total memory allocated from the arena */ + +static Size MVTotalSize(Pool pool) +{ + MV mv; + Size size = 0; + Ring node, next; + + AVERT(Pool, pool); + mv = Pool2MV(pool); + AVERT(MV, mv); + + RING_FOR(node, &mv->spans, next) { + MVSpan span = RING_ELT(MVSpan, spans, node); + AVERT(MVSpan, span); + size += span->size; + } + + return size; +} + + +/* MVFreeSize -- free memory (unused by client program) */ + +static Size MVFreeSize(Pool pool) +{ + MV mv; + Size size = 0; + Ring node, next; + + AVERT(Pool, pool); + mv = Pool2MV(pool); + AVERT(MV, mv); + + RING_FOR(node, &mv->spans, next) { + MVSpan span = RING_ELT(MVSpan, spans, node); + AVERT(MVSpan, span); + size += span->free; + } + + AVER(size == mv->free + mv->lost); + return size; +} + + static Res MVDescribe(Pool pool, mps_lib_FILE *stream) { Res res; @@ -710,7 +755,8 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream) " extendBy $W\n", (WriteFW)mv->extendBy, " avgSize $W\n", (WriteFW)mv->avgSize, " maxSize $W\n", (WriteFW)mv->maxSize, - " space $P\n", (WriteFP)mv->space, + " free $W\n", (WriteFP)mv->free, + " lost $W\n", (WriteFP)mv->lost, NULL); if(res != ResOK) return res; @@ -725,7 +771,8 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream) res = WriteF(stream, " span $P", (WriteFP)span, " tract $P", (WriteFP)span->tract, - " space $W", (WriteFW)span->space, + " size $W", (WriteFW)span->size, + " free $W", (WriteFW)span->free, " blocks $U", (WriteFU)span->blockCount, " largest ", NULL); @@ -806,6 +853,8 @@ DEFINE_POOL_CLASS(MVPoolClass, this) this->finish = MVFinish; this->alloc = MVAlloc; this->free = MVFree; + this->totalSize = MVTotalSize; + this->freeSize = MVFreeSize; this->describe = MVDescribe; AVERT(PoolClass, this); } @@ -847,58 +896,6 @@ mps_class_t mps_class_mv_debug(void) } -/* mps_mv_free_size -- free bytes in pool */ - -size_t mps_mv_free_size(mps_pool_t mps_pool) -{ - Pool pool; - MV mv; - MVSpan span; - Size f = 0; - Ring spans, node = NULL, nextNode; /* gcc whinge stop */ - - pool = (Pool)mps_pool; - - AVERT(Pool, pool); - mv = Pool2MV(pool); - AVERT(MV, mv); - - spans = &mv->spans; - RING_FOR(node, spans, nextNode) { - span = RING_ELT(MVSpan, spans, node); - AVERT(MVSpan, span); - f += span->space; - } - - return (size_t)f; -} - - -size_t mps_mv_size(mps_pool_t mps_pool) -{ - Pool pool; - MV mv; - MVSpan span; - Size f = 0; - Ring spans, node = NULL, nextNode; /* gcc whinge stop */ - - pool = (Pool)mps_pool; - - AVERT(Pool, pool); - mv = Pool2MV(pool); - AVERT(MV, mv); - - spans = &mv->spans; - RING_FOR(node, spans, nextNode) { - span = RING_ELT(MVSpan, spans, node); - AVERT(MVSpan, span); - f += span->size; - } - - return (size_t)f; -} - - /* MVCheck -- check the consistency of an MV structure */ Bool MVCheck(MV mv) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index a149178a8ef..412d235970e 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -40,6 +40,8 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn, static void MVTBufferEmpty(Pool pool, Buffer buffer, Addr base, Addr limit); static void MVTFree(Pool pool, Addr base, Size size); static Res MVTDescribe(Pool pool, mps_lib_FILE *stream); +static Size MVTTotalSize(Pool pool); +static Size MVTFreeSize(Pool pool); static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, Bool withReservoirPermit); @@ -146,6 +148,8 @@ DEFINE_POOL_CLASS(MVTPoolClass, this) this->free = MVTFree; this->bufferFill = MVTBufferFill; this->bufferEmpty = MVTBufferEmpty; + this->totalSize = MVTTotalSize; + this->freeSize = MVTFreeSize; this->describe = MVTDescribe; AVERT(PoolClass, this); } @@ -993,6 +997,34 @@ static void MVTFree(Pool pool, Addr base, Size size) } +/* MVTTotalSize -- total memory allocated from the arena */ + +static Size MVTTotalSize(Pool pool) +{ + MVT mvt; + + AVERT(Pool, pool); + mvt = Pool2MVT(pool); + AVERT(MVT, mvt); + + return mvt->size; +} + + +/* MVTFreeSize -- free memory (unused by client program) */ + +static Size MVTFreeSize(Pool pool) +{ + MVT mvt; + + AVERT(Pool, pool); + mvt = Pool2MVT(pool); + AVERT(MVT, mvt); + + return mvt->available + mvt->unavailable; +} + + /* MVTDescribe -- describe an MVT pool */ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) @@ -1093,44 +1125,6 @@ mps_class_t mps_class_mvt(void) } -/* MPS Interface extensions --- should these be pool generics? */ - - -/* mps_mvt_size -- number of bytes committed to the pool */ - -size_t mps_mvt_size(mps_pool_t mps_pool) -{ - Pool pool; - MVT mvt; - - pool = (Pool)mps_pool; - - AVERT(Pool, pool); - mvt = Pool2MVT(pool); - AVERT(MVT, mvt); - - return (size_t)mvt->size; -} - - -/* mps_mvt_free_size -- number of bytes comitted to the pool that are - * available for allocation - */ -size_t mps_mvt_free_size(mps_pool_t mps_pool) -{ - Pool pool; - MVT mvt; - - pool = (Pool)mps_pool; - - AVERT(Pool, pool); - mvt = Pool2MVT(pool); - AVERT(MVT, mvt); - - return (size_t)mvt->available; -} - - /* Internal methods */ diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 2e38c25aa3d..977fd34b085 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -639,6 +639,34 @@ static PoolDebugMixin MVFFDebugMixin(Pool pool) } +/* MVFFTotalSize -- total memory allocated from the arena */ + +static Size MVFFTotalSize(Pool pool) +{ + MVFF mvff; + + AVERT(Pool, pool); + mvff = Pool2MVFF(pool); + AVERT(MVFF, mvff); + + return LandSize(MVFFTotalCBS(mvff)); +} + + +/* MVFFFreeSize -- free memory (unused by client program) */ + +static Size MVFFFreeSize(Pool pool) +{ + MVFF mvff; + + AVERT(Pool, pool); + mvff = Pool2MVFF(pool); + AVERT(MVFF, mvff); + + return LandSize(MVFFFailover(mvff)); +} + + /* MVFFDescribe -- describe an MVFF pool */ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream) @@ -695,6 +723,8 @@ DEFINE_POOL_CLASS(MVFFPoolClass, this) this->free = MVFFFree; this->bufferFill = MVFFBufferFill; this->bufferEmpty = MVFFBufferEmpty; + this->totalSize = MVFFTotalSize; + this->freeSize = MVFFFreeSize; this->describe = MVFFDescribe; AVERT(PoolClass, this); } @@ -734,37 +764,6 @@ mps_class_t mps_class_mvff_debug(void) } -/* Total free bytes. See */ - -size_t mps_mvff_free_size(mps_pool_t mps_pool) -{ - Pool pool; - MVFF mvff; - - pool = (Pool)mps_pool; - AVERT(Pool, pool); - mvff = Pool2MVFF(pool); - AVERT(MVFF, mvff); - - return (size_t)LandSize(MVFFFailover(mvff)); -} - -/* Total owned bytes. See */ - -size_t mps_mvff_size(mps_pool_t mps_pool) -{ - Pool pool; - MVFF mvff; - - pool = (Pool)mps_pool; - AVERT(Pool, pool); - mvff = Pool2MVFF(pool); - AVERT(MVFF, mvff); - - return (size_t)LandSize(MVFFTotalCBS(mvff)); -} - - /* MVFFCheck -- check the consistency of an MVFF structure */ ATTRIBUTE_UNUSED diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index 139865fc5ec..98a9bb82dad 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -24,9 +24,6 @@ SRCID(poolsnc, "$Id$"); -#define SNCGen ((Serial)1) /* "generation" for SNC pools */ - - /* SNCStruct -- structure for an SNC pool * * See design.mps.poolsnc.poolstruct. diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index d3b657cd6a5..a85e6fdd57e 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -39,6 +39,9 @@ New features was considered, and a chain was collected up to, but not including, the lowest generation whose new size was within its capacity.) +#. New pool introspection functions :c:func:`mps_pool_total_size` and + :c:func:`mps_pool_free_size`. + Interface changes ................. diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst index 5fe096f9aeb..0ba60e8c1ce 100644 --- a/mps/manual/source/topic/pool.rst +++ b/mps/manual/source/topic/pool.rst @@ -135,6 +135,31 @@ See the :ref:`pool` for a list of pool classes. Pool introspection ------------------ +.. c:function:: size_t mps_pool_total_size(mps_pool_t pool) + + Return the total memory allocated from the arena and managed by + the pool. + + ``pool`` is the pool. + + The result includes memory in use by the client program, memory + that's available for use by the client program, and memory + that's lost to fragmentation. It does not include memory used by + the pool's internal control structures. + + +.. c:function:: size_t mps_pool_free_size(mps_pool_t pool) + + Return the free memory: memory managed by the pool but not in use + by the client program. + + ``pool`` is the pool. + + The result includes memory that's available for use by the client + program, and memory that's lost to fragmentation. It does not + include memory used by the pool's internal control structures. + + .. c:function:: mps_bool_t mps_addr_pool(mps_pool_t *pool_o, mps_arena_t arena, mps_addr_t addr) Determine the :term:`pool` to which an address belongs.