diff --git a/mps/code/apss.c b/mps/code/apss.c index 55717dbfeeb..7ee07d356bd 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/misc.h b/mps/code/misc.h index 3d0f259ff72..c07647f54db 100644 --- a/mps/code/misc.h +++ b/mps/code/misc.h @@ -156,13 +156,12 @@ typedef const struct SrcIdStruct { * * Use these values for unused pointer, size closure arguments and * check them in the callback or visitor. - * - * We use PointerAdd rather than a cast to avoid "warning C4306: 'type - * cast' : conversion from 'unsigned int' to 'Pointer' of greater - * size" on platform w3i6mv. + * + * Ensure that they have high bits set on 64-bit platforms for maximum + * unusability. */ -#define UNUSED_POINTER PointerAdd(0, 0xB60405ED) /* PointeR UNUSED */ -#define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */ +#define UNUSED_POINTER (Pointer)((Word)~0xFFFFFFFF | (Word)0xB60405ED) /* PointeR UNUSED */ +#define UNUSED_SIZE ((Size)~0xFFFFFFFF | (Size)0x520405ED) /* SiZe UNUSED */ /* PARENT -- parent structure diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 242cf1d70b7..94be916add8 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -224,6 +224,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, @@ -277,6 +280,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 f881459ba2e..078c0d6ff68 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -24,9 +24,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) { @@ -35,8 +46,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) @@ -49,8 +62,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); @@ -73,13 +88,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 cc3b756c989..fabc1f5edb7 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, Count depth); typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool); +typedef Size (*PoolSizeMethod)(Pool pool); /* Messages diff --git a/mps/code/mps.h b/mps/code/mps.h index d7279c3c726..c9260cc6715 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..5c6522ae1e9 100644 --- a/mps/code/mpscmv.h +++ b/mps/code/mpscmv.h @@ -9,8 +9,9 @@ #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 mps_pool_free_size +#define mps_mv_size mps_pool_total_size + extern mps_class_t mps_class_mv(void); extern mps_class_t mps_class_mv_debug(void); diff --git a/mps/code/mpscmv2.h b/mps/code/mpscmv2.h index 8586a639901..8925d38d3b3 100644 --- a/mps/code/mpscmv2.h +++ b/mps/code/mpscmv2.h @@ -1,27 +1,24 @@ /* mpscmv2.h: MEMORY POOL SYSTEM CLASS "MVT" * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * + * The MVT pool class used to be known as "MV2" in some places: this + * header provides backwards compatibility for prograns that included + * it under its old name. */ #ifndef mpscmv2_h #define mpscmv2_h -#include "mps.h" - -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); +#include "mpscmvt.h" #endif /* mpscmv2_h */ /* 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/mpscmvff.h b/mps/code/mpscmvff.h index f8bc97b7f3b..ca1fbcae697 100644 --- a/mps/code/mpscmvff.h +++ b/mps/code/mpscmvff.h @@ -19,8 +19,9 @@ 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 mps_pool_free_size +#define mps_mvff_size mps_pool_total_size + 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..9490d5ffb77 100644 --- a/mps/code/mpscmvt.h +++ b/mps/code/mpscmvt.h @@ -16,28 +16,10 @@ extern const struct mps_key_s _mps_key_mvt_frag_limit; #define MPS_KEY_MVT_FRAG_LIMIT (&_mps_key_mvt_frag_limit) #define MPS_KEY_MVT_FRAG_LIMIT_FIELD d -/* The mvt pool class has five extra parameters to mps_pool_create: - * mps_res_t mps_pool_create(mps_pool_t * pool, mps_arena_t arena, - * mps_class_t mvt_class, - * size_t minimum_size, - * size_t mean_size, - * size_t maximum_size, - * mps_count_t reserve_depth - * mps_count_t fragmentation_limit); - * minimum_, mean_, and maximum_size are the mimimum, mean, and - * maximum (typical) size of objects expected to be allocated in the - * pool. reserve_depth is a measure of the expected hysteresis of the - * object population. fragmentation_limit is a percentage (between 0 - * and 100): if the free space managed by the pool exceeds the - * specified percentage, the pool will resort to a "first fit" - * allocation policy. - */ 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); +#define mps_mvt_free_size mps_pool_free_size +#define mps_mvt_size mps_pool_total_size #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 84cefee12db..d4fcbc36efc 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; } @@ -518,6 +520,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, Count depth) diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 0d47e5c19f9..ecc05abb2ad 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -145,6 +145,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; } @@ -677,6 +679,14 @@ BufferClass PoolNoBufferClass(void) } +Size PoolNoSize(Pool pool) +{ + AVERT(Pool, pool); + NOTREACHED; + return UNUSED_SIZE; +} + + /* C. COPYRIGHT AND LICENSE * * Copyright (C) 2001-2014 Ravenbrook Limited . diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index df73ad53256..4b90357db45 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -2272,6 +2272,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 = PoolAMC(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 = PoolAMC(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 . @@ -2367,6 +2411,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 5a58e1d27f0..68f368702aa 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -1659,6 +1659,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 = PoolAMS(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 = PoolAMS(pool); + AVERT(AMS, ams); + + return ams->pgen.freeSize; +} + + /* AMSDescribe -- the pool class description method * * Iterates over the segments, describing all of them. @@ -1728,6 +1756,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 0ae1e4221e0..888f6cd42e7 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1282,6 +1282,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 = PoolAWL(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 = PoolAWL(pool); + AVERT(AWL, awl); + + return awl->pgen.freeSize; +} + + /* AWLPoolClass -- the class definition */ DEFINE_POOL_CLASS(AWLPoolClass, this) @@ -1306,6 +1334,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 800864e1a3b..a690df298d8 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -794,6 +794,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) @@ -814,6 +842,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 155e078a41a..8a448f3ae5e 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -116,6 +116,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); @@ -192,6 +194,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. */ @@ -265,6 +271,8 @@ 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; + AVER(mfs->free >= mfs->unitSize); + mfs->free -= mfs->unitSize; *pReturn = (Addr)f; return ResOK; @@ -293,6 +301,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; } @@ -331,6 +368,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); } @@ -365,6 +404,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 b297a4941be..1f8d6c0d96f 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 = PoolMV(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 = PoolMV(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, Count depth) { Res res; @@ -710,7 +755,8 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) "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; @@ -728,7 +774,7 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth + 2, "span $P\n", (WriteFP)span, "tract $P\n", (WriteFP)span->tract, - "space $W\n", (WriteFW)span->space, + "free $W\n", (WriteFW)span->free, "blocks $U\n", (WriteFU)span->blockCount, "largest ", NULL); @@ -794,6 +840,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); } @@ -835,58 +883,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 = PoolMV(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 = PoolMV(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 534a9e2a18d..051ba0af63d 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, Count depth); +static Size MVTTotalSize(Pool pool); +static Size MVTFreeSize(Pool pool); static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, Bool withReservoirPermit); @@ -145,6 +147,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); } @@ -987,6 +991,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 = PoolMVT(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 = PoolMVT(pool); + AVERT(MVT, mvt); + + return mvt->available + mvt->unavailable; +} + + /* MVTDescribe -- describe an MVT pool */ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth) @@ -1088,44 +1120,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 = PoolMVT(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 = PoolMVT(pool); - AVERT(MVT, mvt); - - return (size_t)mvt->available; -} - - /* Internal methods */ diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index e1c1c484dfe..e9620079e13 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -636,6 +636,34 @@ static PoolDebugMixin MVFFDebugMixin(Pool pool) } +/* MVFFTotalSize -- total memory allocated from the arena */ + +static Size MVFFTotalSize(Pool pool) +{ + MVFF mvff; + + AVERT(Pool, pool); + mvff = PoolMVFF(pool); + AVERT(MVFF, mvff); + + return LandSize(MVFFTotalLand(mvff)); +} + + +/* MVFFFreeSize -- free memory (unused by client program) */ + +static Size MVFFFreeSize(Pool pool) +{ + MVFF mvff; + + AVERT(Pool, pool); + mvff = PoolMVFF(pool); + AVERT(MVFF, mvff); + + return LandSize(MVFFFreeLand(mvff)); +} + + /* MVFFDescribe -- describe an MVFF pool */ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth) @@ -693,6 +721,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); } @@ -732,37 +762,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 = PoolMVFF(pool); - AVERT(MVFF, mvff); - - return (size_t)LandSize(MVFFFreeLand(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 = PoolMVFF(pool); - AVERT(MVFF, mvff); - - return (size_t)LandSize(MVFFTotalLand(mvff)); -} - - /* MVFFCheck -- check the consistency of an MVFF structure */ ATTRIBUTE_UNUSED diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index 5fd44c9786d..9263b06bbd5 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 f25292c52df..a866fb566f4 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.