1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-22 21:50:45 -08:00

Catch-up merge from master sources @186564 to branch/2014-06-11/grain.

Copied from Perforce
 Change: 186572
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2014-06-13 15:30:46 +01:00
commit a13a1aa1df
109 changed files with 2685 additions and 1997 deletions

View file

@ -156,7 +156,7 @@ Bool ABQPeek(ABQ abq, void *elementReturn)
/* ABQDescribe -- Describe an ABQ */ /* ABQDescribe -- Describe an ABQ */
Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream) Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Index index; Index index;
@ -164,8 +164,8 @@ Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *strea
if (!TESTT(ABQ, abq)) return ResFAIL; if (!TESTT(ABQ, abq)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"ABQ $P\n{\n", (WriteFP)abq, "ABQ $P {\n", (WriteFP)abq,
" elements: $U \n", (WriteFU)abq->elements, " elements: $U \n", (WriteFU)abq->elements,
" in: $U \n", (WriteFU)abq->in, " in: $U \n", (WriteFU)abq->in,
" out: $U \n", (WriteFU)abq->out, " out: $U \n", (WriteFU)abq->out,
@ -175,22 +175,18 @@ Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *strea
return res; return res;
for (index = abq->out; index != abq->in; ) { for (index = abq->out; index != abq->in; ) {
res = (*describeElement)(ABQElement(abq, index), stream); res = (*describeElement)(ABQElement(abq, index), stream, depth + 2);
if(res != ResOK) if(res != ResOK)
return res; return res;
index = ABQNextIndex(abq, index); index = ABQNextIndex(abq, index);
} }
res = WriteF(stream, "\n", NULL); METER_WRITE(abq->push, stream, depth + 2);
if(res != ResOK) METER_WRITE(abq->pop, stream, depth + 2);
return res; METER_WRITE(abq->peek, stream, depth + 2);
METER_WRITE(abq->delete, stream, depth + 2);
METER_WRITE(abq->push, stream); res = WriteF(stream, depth, "} ABQ $P\n", (WriteFP)abq, NULL);
METER_WRITE(abq->pop, stream);
METER_WRITE(abq->peek, stream);
METER_WRITE(abq->delete, stream);
res = WriteF(stream, "}\n", NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;

View file

@ -23,7 +23,7 @@
/* Prototypes */ /* Prototypes */
typedef struct ABQStruct *ABQ; typedef struct ABQStruct *ABQ;
typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream); typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream, Count depth);
typedef Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS); typedef Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS);
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize); extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize);
@ -32,7 +32,7 @@ extern void ABQFinish(Arena arena, ABQ abq);
extern Bool ABQPush(ABQ abq, void *element); extern Bool ABQPush(ABQ abq, void *element);
extern Bool ABQPop(ABQ abq, void *elementReturn); extern Bool ABQPop(ABQ abq, void *elementReturn);
extern Bool ABQPeek(ABQ abq, void *elementReturn); extern Bool ABQPeek(ABQ abq, void *elementReturn);
extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream); extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream, Count depth);
extern Bool ABQIsEmpty(ABQ abq); extern Bool ABQIsEmpty(ABQ abq);
extern Bool ABQIsFull(ABQ abq); extern Bool ABQIsFull(ABQ abq);
extern Count ABQDepth(ABQ abq); extern Count ABQDepth(ABQ abq);

View file

@ -8,6 +8,7 @@
#include "fmtdy.h" #include "fmtdy.h"
#include "fmtdytst.h" #include "fmtdytst.h"
#include "testlib.h" #include "testlib.h"
#include "mpm.h"
#include "mpslib.h" #include "mpslib.h"
#include "mpscamc.h" #include "mpscamc.h"
#include "mpsavm.h" #include "mpsavm.h"
@ -20,7 +21,7 @@
/* These values have been tuned in the hope of getting one dynamic collection. */ /* These values have been tuned in the hope of getting one dynamic collection. */
#define testArenaSIZE ((size_t)1000*1024) #define testArenaSIZE ((size_t)1000*1024)
#define gen1SIZE ((size_t)150) #define gen1SIZE ((size_t)40)
#define gen2SIZE ((size_t)170) #define gen2SIZE ((size_t)170)
#define avLEN 3 #define avLEN 3
#define exactRootsCOUNT 180 #define exactRootsCOUNT 180
@ -135,6 +136,7 @@ static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count)
mps_ap_t busy_ap; mps_ap_t busy_ap;
mps_addr_t busy_init; mps_addr_t busy_init;
mps_pool_t pool; mps_pool_t pool;
int described = 0;
die(dylan_fmt(&format, arena), "fmt_create"); die(dylan_fmt(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
@ -175,6 +177,10 @@ static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count)
c = mps_collections(arena); c = mps_collections(arena);
if (collections != c) { if (collections != c) {
if (!described) {
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
described = TRUE;
}
collections = c; collections = c;
report(arena); report(arena);

View file

@ -16,6 +16,7 @@
#include "mpsavm.h" #include "mpsavm.h"
#include "mpstd.h" #include "mpstd.h"
#include "mps.h" #include "mps.h"
#include "mpm.h"
#include <stdio.h> /* fflush, printf */ #include <stdio.h> /* fflush, printf */
@ -141,6 +142,8 @@ static void test_pool(mps_class_t pool_class, mps_arg_s args[],
/* create an ap, and leave it busy */ /* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
die(PoolDescribe(pool, mps_lib_get_stdout(), 0), "PoolDescribe");
objs = 0; totalSize = 0; objs = 0; totalSize = 0;
while(totalSize < totalSizeMAX) { while(totalSize < totalSizeMAX) {
if (totalSize > lastStep + totalSizeSTEP) { if (totalSize > lastStep + totalSizeSTEP) {

View file

@ -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_size = mps_pool_total_size(pool);
size_t free_size = mps_pool_free_size(pool);
size_t ap_free = (size_t)((char *)ap->limit - (char *)ap->init);
Insist(total_size - free_size == allocated + ap_free);
}
/* stress -- create a pool of the requested type and allocate in it */ /* 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), size_t (*size)(size_t i, mps_align_t align),
const char *name, mps_class_t class, mps_arg_s args[]) 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; size_t i, k;
int *ps[testSetSIZE]; int *ps[testSetSIZE];
size_t ss[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); 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]); res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK) if (res != MPS_RES_OK)
goto allocFail; goto allocFail;
allocated += ss[i] + debugOverhead;
if (ss[i] >= sizeof(ps[i])) if (ss[i] >= sizeof(ps[i]))
*ps[i] = 1; /* Write something, so it gets swap. */ *ps[i] = 1; /* Write something, so it gets swap. */
check_allocated_size(pool, ap, allocated);
} }
mps_pool_check_fenceposts(pool); 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]); mps_free(pool, (mps_addr_t)ps[i], ss[i]);
/* if (i == testSetSIZE/2) */ /* if (i == testSetSIZE/2) */
/* PoolDescribe((Pool)pool, mps_lib_stdout); */ /* PoolDescribe((Pool)pool, mps_lib_stdout); */
Insist(ss[i] + debugOverhead <= allocated);
allocated -= ss[i] + debugOverhead;
} }
/* allocate some new objects */ /* allocate some new objects */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) { for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
@ -97,7 +115,9 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align,
res = make((mps_addr_t *)&ps[i], ap, ss[i]); res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK) if (res != MPS_RES_OK)
goto allocFail; goto allocFail;
allocated += ss[i] + debugOverhead;
} }
check_allocated_size(pool, ap, allocated);
} }
allocFail: allocFail:
@ -145,8 +165,8 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
die(stress(arena, align, randomSizeAligned, "MVFF", mps_class_mvff(), args), die(stress(arena, NULL, align, randomSizeAligned, "MVFF",
"stress MVFF"); mps_class_mvff(), args), "stress MVFF");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */ /* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */
@ -155,24 +175,23 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6); mps_align_t align = (mps_align_t)1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, align, randomSizeAligned, "MV", mps_class_mv(), args), die(stress(arena, NULL, align, randomSizeAligned, "MV",
"stress MV"); mps_class_mv(), args), "stress MV");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6); mps_align_t align = (mps_align_t)1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, align, randomSizeAligned, "MV debug", die(stress(arena, options, align, randomSizeAligned, "MV debug",
mps_class_mv_debug(), args), mps_class_mv_debug(), args), "stress MV debug");
"stress MV debug");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4); mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, align, randomSizeAligned, "MVT", mps_class_mvt(), args), die(stress(arena, NULL, align, randomSizeAligned, "MVT",
"stress MVT"); mps_class_mvt(), args), "stress MVT");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
} }

View file

@ -17,9 +17,9 @@
SRCID(arena, "$Id$"); SRCID(arena, "$Id$");
#define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct) #define ArenaControlPool(arena) MVPool(&(arena)->controlPoolStruct)
#define ArenaCBSBlockPool(arena) (&(arena)->freeCBSBlockPoolStruct.poolStruct) #define ArenaCBSBlockPool(arena) MFSPool(&(arena)->freeCBSBlockPoolStruct)
#define ArenaFreeLand(arena) (&(arena)->freeLandStruct.landStruct) #define ArenaFreeLand(arena) CBSLand(&(arena)->freeLandStruct)
/* ArenaGrainSizeCheck -- check that size is a valid arena grain size */ /* ArenaGrainSizeCheck -- check that size is a valid arena grain size */
@ -45,7 +45,7 @@ static void arenaFreePage(Arena arena, Addr base, Pool pool);
/* ArenaTrivDescribe -- produce trivial description of an arena */ /* ArenaTrivDescribe -- produce trivial description of an arena */
static Res ArenaTrivDescribe(Arena arena, mps_lib_FILE *stream) static Res ArenaTrivDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{ {
if (!TESTT(Arena, arena)) return ResFAIL; if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
@ -62,7 +62,7 @@ static Res ArenaTrivDescribe(Arena arena, mps_lib_FILE *stream)
* subclass describe method should avoid invoking * subclass describe method should avoid invoking
* ARENA_SUPERCLASS()->describe. RHSK 2007-04-27. * ARENA_SUPERCLASS()->describe. RHSK 2007-04-27.
*/ */
return WriteF(stream, return WriteF(stream, depth,
" No class-specific description available.\n", NULL); " No class-specific description available.\n", NULL);
} }
@ -162,8 +162,10 @@ Bool ArenaCheck(Arena arena)
CHECKD(Chunk, arena->primary); CHECKD(Chunk, arena->primary);
} }
CHECKD_NOSIG(Ring, &arena->chunkRing); CHECKD_NOSIG(Ring, &arena->chunkRing);
/* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */
CHECKL(TreeCheck(ArenaChunkTree(arena)));
/* TODO: check that the chunkRing and chunkTree have identical members */
/* nothing to check for chunkSerial */ /* nothing to check for chunkSerial */
CHECKD(ChunkCacheEntry, &arena->chunkCache);
CHECKL(LocusCheck(arena)); CHECKL(LocusCheck(arena));
@ -220,8 +222,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->primary = NULL; arena->primary = NULL;
RingInit(&arena->chunkRing); RingInit(&arena->chunkRing);
arena->chunkTree = TreeEMPTY;
arena->chunkSerial = (Serial)0; arena->chunkSerial = (Serial)0;
ChunkCacheEntryInit(&arena->chunkCache);
LocusInit(arena); LocusInit(arena);
@ -321,13 +323,13 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
/* With the primary chunk initialised we can add page memory to the freeLand /* With the primary chunk initialised we can add page memory to the freeLand
that describes the free address space in the primary chunk. */ that describes the free address space in the primary chunk. */
arena->hasFreeLand = TRUE;
res = ArenaFreeLandInsert(arena, res = ArenaFreeLandInsert(arena,
PageIndexBase(arena->primary, PageIndexBase(arena->primary,
arena->primary->allocBase), arena->primary->allocBase),
arena->primary->limit); arena->primary->limit);
if (res != ResOK) if (res != ResOK)
goto failPrimaryLand; goto failPrimaryLand;
arena->hasFreeLand = TRUE;
res = ControlInit(arena); res = ControlInit(arena);
if (res != ResOK) if (res != ResOK)
@ -360,11 +362,13 @@ failInit:
void ArenaFinish(Arena arena) void ArenaFinish(Arena arena)
{ {
PoolFinish(ArenaCBSBlockPool(arena));
ReservoirFinish(ArenaReservoir(arena)); ReservoirFinish(ArenaReservoir(arena));
arena->sig = SigInvalid; arena->sig = SigInvalid;
GlobalsFinish(ArenaGlobals(arena)); GlobalsFinish(ArenaGlobals(arena));
LocusFinish(arena); LocusFinish(arena);
RingFinish(&arena->chunkRing); RingFinish(&arena->chunkRing);
AVER(ArenaChunkTree(arena) == TreeEMPTY);
} }
@ -405,7 +409,6 @@ void ArenaDestroy(Arena arena)
that would use the freeLand. */ that would use the freeLand. */
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
UNUSED_POINTER, UNUSED_SIZE); UNUSED_POINTER, UNUSED_SIZE);
PoolFinish(ArenaCBSBlockPool(arena));
/* Call class-specific finishing. This will call ArenaFinish. */ /* Call class-specific finishing. This will call ArenaFinish. */
(*arena->class->finish)(arena); (*arena->class->finish)(arena);
@ -423,7 +426,7 @@ Res ControlInit(Arena arena)
AVERT(Arena, arena); AVERT(Arena, arena);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY); MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY);
res = PoolInit(&arena->controlPoolStruct.poolStruct, arena, res = PoolInit(MVPool(&arena->controlPoolStruct), arena,
PoolClassMV(), args); PoolClassMV(), args);
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
if (res != ResOK) if (res != ResOK)
@ -439,13 +442,13 @@ void ControlFinish(Arena arena)
{ {
AVERT(Arena, arena); AVERT(Arena, arena);
arena->poolReady = FALSE; arena->poolReady = FALSE;
PoolFinish(&arena->controlPoolStruct.poolStruct); PoolFinish(MVPool(&arena->controlPoolStruct));
} }
/* ArenaDescribe -- describe the arena */ /* ArenaDescribe -- describe the arena */
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream) Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Size reserved; Size reserved;
@ -453,14 +456,14 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
if (!TESTT(Arena, arena)) return ResFAIL; if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, "Arena $P {\n", (WriteFP)arena, res = WriteF(stream, depth, "Arena $P {\n", (WriteFP)arena,
" class $P (\"$S\")\n", " class $P (\"$S\")\n",
(WriteFP)arena->class, arena->class->name, (WriteFP)arena->class, arena->class->name,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (arena->poolReady) { if (arena->poolReady) {
res = WriteF(stream, res = WriteF(stream, depth + 2,
"controlPool $P\n", (WriteFP)&arena->controlPoolStruct, "controlPool $P\n", (WriteFP)&arena->controlPoolStruct,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
@ -468,14 +471,14 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
/* Note: this Describe clause calls a function */ /* Note: this Describe clause calls a function */
reserved = ArenaReserved(arena); reserved = ArenaReserved(arena);
res = WriteF(stream, res = WriteF(stream, depth + 2,
"reserved $W <-- " "reserved $W <-- "
"total size of address-space reserved\n", "total size of address-space reserved\n",
(WriteFW)reserved, (WriteFW)reserved,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth + 2,
"committed $W <-- " "committed $W <-- "
"total bytes currently stored (in RAM or swap)\n", "total bytes currently stored (in RAM or swap)\n",
(WriteFW)arena->committed, (WriteFW)arena->committed,
@ -487,24 +490,23 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth + 2,
"droppedMessages $U$S\n", (WriteFU)arena->droppedMessages, "droppedMessages $U$S\n", (WriteFU)arena->droppedMessages,
(arena->droppedMessages == 0 ? "" : " -- MESSAGES DROPPED!"), (arena->droppedMessages == 0 ? "" : " -- MESSAGES DROPPED!"),
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = (*arena->class->describe)(arena, stream); res = (*arena->class->describe)(arena, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
/* Do not call GlobalsDescribe: it makes too much output, thanks. res = WriteF(stream, depth + 2, "Globals {\n", NULL);
* RHSK 2007-04-27 if (res != ResOK) return res;
*/ res = GlobalsDescribe(ArenaGlobals(arena), stream, depth + 4);
#if 0 if (res != ResOK) return res;
res = GlobalsDescribe(ArenaGlobals(arena), stream); res = WriteF(stream, depth + 2, "} Globals\n", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
#endif
res = WriteF(stream, res = WriteF(stream, depth,
"} Arena $P ($U)\n", (WriteFP)arena, "} Arena $P ($U)\n", (WriteFP)arena,
(WriteFU)arena->serial, (WriteFU)arena->serial,
NULL); NULL);
@ -512,47 +514,68 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
} }
/* ArenaDescribeTracts -- describe all the tracts in the arena */ /* arenaDescribeTractsInChunk -- describe the tracts in a chunk */
Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream) static Res arenaDescribeTractsInChunk(Chunk chunk, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Tract tract; Index pi;
Bool b;
Addr oldLimit, base, limit; if (stream == NULL) return ResFAIL;
Size size; if (!TESTT(Chunk, chunk)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = WriteF(stream, depth, "Chunk [$P, $P) ($U) {\n",
(WriteFP)chunk->base, (WriteFP)chunk->limit,
(WriteFU)chunk->serial,
NULL);
if (res != ResOK) return res;
for (pi = chunk->allocBase; pi < chunk->pages; ++pi) {
if (BTGet(chunk->allocTable, pi)) {
Tract tract = PageTract(ChunkPage(chunk, pi));
res = WriteF(stream, depth + 2, "[$P, $P)",
(WriteFP)TractBase(tract),
(WriteFP)TractLimit(tract, ChunkArena(chunk)),
NULL);
if (res != ResOK) return res;
if (TractHasPool(tract)) {
Pool pool = TractPool(tract);
res = WriteF(stream, 0, " $P $U ($S)",
(WriteFP)pool,
(WriteFU)(pool->serial),
(WriteFS)(pool->class->name),
NULL);
if (res != ResOK) return res;
}
res = WriteF(stream, 0, "\n", NULL);
if (res != ResOK) return res;
}
}
res = WriteF(stream, depth, "} Chunk [$P, $P)\n",
(WriteFP)chunk->base, (WriteFP)chunk->limit,
NULL);
return res;
}
/* ArenaDescribeTracts -- describe all the tracts in the arena */
Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth)
{
Ring node, next;
Res res;
if (!TESTT(Arena, arena)) return ResFAIL; if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
b = TractFirst(&tract, arena); RING_FOR(node, &arena->chunkRing, next) {
oldLimit = TractBase(tract); Chunk chunk = RING_ELT(Chunk, chunkRing, node);
while (b) { res = arenaDescribeTractsInChunk(chunk, stream, depth);
base = TractBase(tract);
limit = TractLimit(tract);
size = ArenaGrainSize(arena);
if (TractBase(tract) > oldLimit) {
res = WriteF(stream,
"[$P, $P) $W $U ---\n",
(WriteFP)oldLimit, (WriteFP)base,
(WriteFW)AddrOffset(oldLimit, base),
(WriteFU)AddrOffset(oldLimit, base),
NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream,
"[$P, $P) $W $U $P ($S)\n",
(WriteFP)base, (WriteFP)limit,
(WriteFW)size, (WriteFW)size,
(WriteFP)TractPool(tract),
(WriteFS)(TractPool(tract)->class->name),
NULL);
if (res != ResOK) return res;
b = TractNext(&tract, arena, TractBase(tract));
oldLimit = limit;
}
return ResOK; return ResOK;
} }
@ -603,19 +626,38 @@ void ControlFree(Arena arena, void* base, size_t size)
/* ControlDescribe -- describe the arena's control pool */ /* ControlDescribe -- describe the arena's control pool */
Res ControlDescribe(Arena arena, mps_lib_FILE *stream) Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
if (!TESTT(Arena, arena)) return ResFAIL; if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = PoolDescribe(ArenaControlPool(arena), stream); res = PoolDescribe(ArenaControlPool(arena), stream, depth);
return res; return res;
} }
/* ArenaChunkInsert -- insert chunk into arena's chunk tree */
void ArenaChunkInsert(Arena arena, Chunk chunk) {
Bool inserted;
Tree tree, updatedTree = NULL;
AVERT(Arena, arena);
AVERT(Chunk, chunk);
tree = &chunk->chunkTree;
inserted = TreeInsert(&updatedTree, ArenaChunkTree(arena),
tree, ChunkKey(tree), ChunkCompare);
AVER(inserted && updatedTree);
TreeBalance(&updatedTree);
arena->chunkTree = updatedTree;
RingAppend(&arena->chunkRing, &chunk->chunkRing);
}
/* arenaAllocPage -- allocate one page from the arena /* arenaAllocPage -- allocate one page from the arena
* *
* This is a primitive allocator used to allocate pages for the arena * This is a primitive allocator used to allocate pages for the arena
@ -654,6 +696,10 @@ static Res arenaAllocPage(Addr *baseReturn, Arena arena, Pool pool)
{ {
Res res; Res res;
AVER(baseReturn != NULL);
AVERT(Arena, arena);
AVERT(Pool, pool);
/* Favour the primary chunk, because pages allocated this way aren't /* Favour the primary chunk, because pages allocated this way aren't
currently freed, and we don't want to prevent chunks being destroyed. */ currently freed, and we don't want to prevent chunks being destroyed. */
/* TODO: Consider how the ArenaCBSBlockPool might free pages. */ /* TODO: Consider how the ArenaCBSBlockPool might free pages. */
@ -899,7 +945,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
/* Step 2. Make memory available in the address space range. */ /* Step 2. Make memory available in the address space range. */
b = CHUNK_OF_ADDR(&chunk, arena, RangeBase(&range)); b = ChunkOfAddr(&chunk, arena, RangeBase(&range));
AVER(b); AVER(b);
AVER(RangeIsAligned(&range, ChunkPageSize(chunk))); AVER(RangeIsAligned(&range, ChunkPageSize(chunk)));
baseIndex = INDEX_OF_ADDR(chunk, RangeBase(&range)); baseIndex = INDEX_OF_ADDR(chunk, RangeBase(&range));

View file

@ -173,15 +173,26 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
/* clientChunkDestroy -- destroy a ClientChunk */ /* clientChunkDestroy -- destroy a ClientChunk */
static void clientChunkDestroy(Chunk chunk) static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
{ {
Chunk chunk;
ClientChunk clChunk; ClientChunk clChunk;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
UNUSED(closureP);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
clChunk = Chunk2ClientChunk(chunk); clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk); AVERT(ClientChunk, clChunk);
clChunk->sig = SigInvalid; clChunk->sig = SigInvalid;
ChunkFinish(chunk); ChunkFinish(chunk);
return TRUE;
} }
@ -290,16 +301,15 @@ failChunkCreate:
static void ClientArenaFinish(Arena arena) static void ClientArenaFinish(Arena arena)
{ {
ClientArena clientArena; ClientArena clientArena;
Ring node, next;
clientArena = Arena2ClientArena(arena); clientArena = Arena2ClientArena(arena);
AVERT(ClientArena, clientArena); AVERT(ClientArena, clientArena);
/* destroy all chunks */ /* Destroy all chunks, including the primary. See
RING_FOR(node, &arena->chunkRing, next) { * <design/arena/#chunk.delete> */
Chunk chunk = RING_ELT(Chunk, chunkRing, node); arena->primary = NULL;
clientChunkDestroy(chunk); TreeTraverseAndDelete(&arena->chunkTree, clientChunkDestroy,
} UNUSED_POINTER, UNUSED_SIZE);
clientArena->sig = SigInvalid; clientArena->sig = SigInvalid;
@ -341,7 +351,7 @@ static Size ClientArenaReserved(Arena arena)
RING_FOR(node, &arena->chunkRing, nextNode) { RING_FOR(node, &arena->chunkRing, nextNode) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node); Chunk chunk = RING_ELT(Chunk, chunkRing, node);
AVERT(Chunk, chunk); AVERT(Chunk, chunk);
size += AddrOffset(chunk->base, chunk->limit); size += ChunkSize(chunk);
} }
return size; return size;

View file

@ -87,6 +87,73 @@ typedef struct AllocatorClassStruct {
} AllocatorClassStruct; } AllocatorClassStruct;
/* tractSearchInChunk -- find a tract in a chunk
*
* .tract-search: Searches for a tract in the chunk starting at page
* index i, return FALSE if there is none.
*/
static Bool tractSearchInChunk(Tract *tractReturn, Chunk chunk, Index i)
{
AVER_CRITICAL(chunk->allocBase <= i);
AVER_CRITICAL(i <= chunk->pages);
while (i < chunk->pages
&& !(BTGet(chunk->allocTable, i)
&& PageIsAllocated(ChunkPage(chunk, i)))) {
++i;
}
if (i == chunk->pages)
return FALSE;
AVER(i < chunk->pages);
*tractReturn = PageTract(ChunkPage(chunk, i));
return TRUE;
}
/* tractSearch -- find next tract above address
*
* Searches for the next tract in increasing address order.
* The tract returned is the next one along from addr (i.e.,
* it has a base address bigger than addr and no other tract
* with a base address bigger than addr has a smaller base address).
*
* Returns FALSE if there is no tract to find (end of the arena).
*/
static Bool tractSearch(Tract *tractReturn, Arena arena, Addr addr)
{
Bool b;
Chunk chunk;
Tree tree;
b = ChunkOfAddr(&chunk, arena, addr);
if (b) {
Index i;
i = INDEX_OF_ADDR(chunk, addr);
/* There are fewer pages than addresses, therefore the */
/* page index can never wrap around */
AVER_CRITICAL(i+1 != 0);
if (tractSearchInChunk(tractReturn, chunk, i+1)) {
return TRUE;
}
}
while (TreeFindNext(&tree, ArenaChunkTree(arena), TreeKeyOfAddrVar(addr),
ChunkCompare))
{
chunk = ChunkOfTree(tree);
addr = chunk->base;
/* Start from allocBase to skip the tables. */
if (tractSearchInChunk(tractReturn, chunk, chunk->allocBase)) {
return TRUE;
}
}
return FALSE;
}
/* Implementation of the tract-based interchangability interface */ /* Implementation of the tract-based interchangability interface */
static Res allocAsTract(AllocInfoStruct *aiReturn, SegPref pref, static Res allocAsTract(AllocInfoStruct *aiReturn, SegPref pref,
@ -114,7 +181,7 @@ static Bool firstAsTract(AllocInfoStruct *aiReturn, Arena arena)
{ {
Bool res; Bool res;
Tract tract; Tract tract;
res = TractFirst(&tract, arena); res = tractSearch(&tract, arena, 0);
if (res) { if (res) {
aiReturn->the.tractData.base = TractBase(tract); aiReturn->the.tractData.base = TractBase(tract);
aiReturn->the.tractData.size = ArenaGrainSize(arena);; aiReturn->the.tractData.size = ArenaGrainSize(arena);;
@ -128,7 +195,7 @@ static Bool nextAsTract(AllocInfoStruct *nextReturn, AllocInfo ai,
{ {
Bool res; Bool res;
Tract tract; Tract tract;
res = TractNext(&tract, arena, ai->the.tractData.base); res = tractSearch(&tract, arena, ai->the.tractData.base);
if (res) { if (res) {
nextReturn->the.tractData.base = TractBase(tract); nextReturn->the.tractData.base = TractBase(tract);
nextReturn->the.tractData.size = ArenaGrainSize(arena);; nextReturn->the.tractData.size = ArenaGrainSize(arena);;
@ -332,7 +399,6 @@ static void testAllocAndIterate(Arena arena, Pool pool,
} }
SegPrefExpress(&pref, SegPrefZoneSet, &zone); SegPrefExpress(&pref, SegPrefZoneSet, &zone);
} }
} }
@ -363,6 +429,10 @@ static void testPageTable(ArenaClass class, Size size, Addr addr, Bool zoned)
testAllocAndIterate(arena, pool, pageSize, tractsPerPage, testAllocAndIterate(arena, pool, pageSize, tractsPerPage,
&allocatorSegStruct); &allocatorSegStruct);
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
die(ArenaDescribeTracts(arena, mps_lib_get_stdout(), 0),
"ArenaDescribeTracts");
PoolDestroy(pool); PoolDestroy(pool);
ArenaDestroy(arena); ArenaDestroy(arena);
} }

View file

@ -186,7 +186,7 @@ static Bool VMArenaCheck(VMArena vmArena)
/* VMArenaDescribe -- describe the VMArena /* VMArenaDescribe -- describe the VMArena
*/ */
static Res VMArenaDescribe(Arena arena, mps_lib_FILE *stream) static Res VMArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
VMArena vmArena; VMArena vmArena;
@ -206,7 +206,7 @@ static Res VMArenaDescribe(Arena arena, mps_lib_FILE *stream)
* *
*/ */
res = WriteF(stream, res = WriteF(stream, depth,
" spareSize: $U\n", (WriteFU)vmArena->spareSize, " spareSize: $U\n", (WriteFU)vmArena->spareSize,
NULL); NULL);
if(res != ResOK) if(res != ResOK)
@ -401,11 +401,19 @@ failSaMapped:
/* vmChunkDestroy -- destroy a VMChunk */ /* vmChunkDestroy -- destroy a VMChunk */
static void vmChunkDestroy(Chunk chunk) static Bool vmChunkDestroy(Tree tree, void *closureP, Size closureS)
{ {
VM vm; VM vm;
Chunk chunk;
VMChunk vmChunk; VMChunk vmChunk;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
UNUSED(closureP);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk); AVERT(Chunk, chunk);
vmChunk = Chunk2VMChunk(chunk); vmChunk = Chunk2VMChunk(chunk);
AVERT(VMChunk, vmChunk); AVERT(VMChunk, vmChunk);
@ -418,6 +426,8 @@ static void vmChunkDestroy(Chunk chunk)
vm = vmChunk->vm; vm = vmChunk->vm;
ChunkFinish(chunk); ChunkFinish(chunk);
VMDestroy(vm); VMDestroy(vm);
return TRUE;
} }
@ -557,7 +567,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
/* bits in a word). Fail if the chunk is so small stripes are smaller */ /* bits in a word). Fail if the chunk is so small stripes are smaller */
/* than pages. Note that some zones are discontiguous in the chunk if */ /* than pages. Note that some zones are discontiguous in the chunk if */
/* the size is not a power of 2. See <design/arena/#class.fields>. */ /* the size is not a power of 2. See <design/arena/#class.fields>. */
chunkSize = AddrOffset(chunk->base, chunk->limit); chunkSize = ChunkSize(chunk);
arena->zoneShift = SizeFloorLog2(chunkSize >> MPS_WORD_SHIFT); arena->zoneShift = SizeFloorLog2(chunkSize >> MPS_WORD_SHIFT);
AVER(chunk->pageSize == ArenaGrainSize(arena)); AVER(chunk->pageSize == ArenaGrainSize(arena));
@ -588,7 +598,6 @@ failVMCreate:
static void VMArenaFinish(Arena arena) static void VMArenaFinish(Arena arena)
{ {
VMArena vmArena; VMArena vmArena;
Ring node, next;
VM arenaVM; VM arenaVM;
vmArena = Arena2VMArena(arena); vmArena = Arena2VMArena(arena);
@ -597,12 +606,11 @@ static void VMArenaFinish(Arena arena)
EVENT1(ArenaDestroy, vmArena); EVENT1(ArenaDestroy, vmArena);
/* destroy all chunks, including the primary */ /* Destroy all chunks, including the primary. See
* <design/arena/#chunk.delete> */
arena->primary = NULL; arena->primary = NULL;
RING_FOR(node, &arena->chunkRing, next) { TreeTraverseAndDelete(&arena->chunkTree, vmChunkDestroy,
Chunk chunk = RING_ELT(Chunk, chunkRing, node); UNUSED_POINTER, UNUSED_SIZE);
vmChunkDestroy(chunk);
}
/* Destroying the chunks should have purged and removed all spare pages. */ /* Destroying the chunks should have purged and removed all spare pages. */
RingFinish(&vmArena->spareRing); RingFinish(&vmArena->spareRing);
@ -623,6 +631,7 @@ static void VMArenaFinish(Arena arena)
* *
* Add up the reserved space from all the chunks. * Add up the reserved space from all the chunks.
*/ */
static Size VMArenaReserved(Arena arena) static Size VMArenaReserved(Arena arena)
{ {
Size reserved; Size reserved;
@ -943,8 +952,6 @@ static Size chunkUnmapAroundPage(Chunk chunk, Size size, Page page)
* unmapped. * unmapped.
*/ */
#define ArenaChunkRing(arena) (&(arena)->chunkRing)
static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter) static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter)
{ {
Ring node; Ring node;
@ -996,9 +1003,7 @@ static Size VMPurgeSpare(Arena arena, Size size)
static void chunkUnmapSpare(Chunk chunk) static void chunkUnmapSpare(Chunk chunk)
{ {
AVERT(Chunk, chunk); AVERT(Chunk, chunk);
(void)arenaUnmapSpare(ChunkArena(chunk), (void)arenaUnmapSpare(ChunkArena(chunk), ChunkSize(chunk), chunk);
AddrOffset(chunk->base, chunk->limit),
chunk);
} }
@ -1054,8 +1059,9 @@ static void VMFree(Addr base, Size size, Pool pool)
BTResRange(chunk->allocTable, piBase, piLimit); BTResRange(chunk->allocTable, piBase, piLimit);
/* Consider returning memory to the OS. */ /* Consider returning memory to the OS. */
/* TODO: Chunks are only destroyed when ArenaCompact is called, and that is /* TODO: Chunks are only destroyed when ArenaCompact is called, and
only called from TraceReclaim. Should consider destroying chunks here. */ that is only called from traceReclaim. Should consider destroying
chunks here. See job003815. */
if (arena->spareCommitted > arena->spareCommitLimit) { if (arena->spareCommitted > arena->spareCommitLimit) {
/* Purge half of the spare memory, not just the extra sliver, so /* Purge half of the spare memory, not just the extra sliver, so
that we return a reasonable amount of memory in one go, and avoid that we return a reasonable amount of memory in one go, and avoid
@ -1068,10 +1074,41 @@ static void VMFree(Addr base, Size size, Pool pool)
} }
/* vmChunkCompact -- delete chunk if empty and not primary */
static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
{
Chunk chunk;
Arena arena = closureP;
VMArena vmArena;
AVERT(Tree, tree);
AVERT(Arena, arena);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
vmArena = Arena2VMArena(arena);
AVERT(VMArena, vmArena);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
if(chunk != arena->primary
&& BTIsResRange(chunk->allocTable, 0, chunk->pages))
{
Addr base = chunk->base;
Size size = ChunkSize(chunk);
vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE);
vmArena->contracted(arena, base, size);
return TRUE;
} else {
/* Keep this chunk. */
return FALSE;
}
}
static void VMCompact(Arena arena, Trace trace) static void VMCompact(Arena arena, Trace trace)
{ {
VMArena vmArena; VMArena vmArena;
Ring node, next;
Size vmem1; Size vmem1;
vmArena = Arena2VMArena(arena); vmArena = Arena2VMArena(arena);
@ -1080,23 +1117,11 @@ static void VMCompact(Arena arena, Trace trace)
vmem1 = VMArenaReserved(arena); vmem1 = VMArenaReserved(arena);
RING_FOR(node, &arena->chunkRing, next) { /* Destroy chunks that are completely free, but not the primary
Chunk chunk = RING_ELT(Chunk, chunkRing, node); * chunk. See <design/arena/#chunk.delete>
if(chunk != arena->primary * TODO: add hysteresis here. See job003815. */
&& BTIsResRange(chunk->allocTable, 0, chunk->pages)) { TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena,
Addr base = chunk->base; UNUSED_SIZE);
Size size = AddrOffset(chunk->base, chunk->limit);
/* Ensure there are no spare (mapped) pages left in the chunk.
This could be short-cut if we're about to destroy the chunk,
provided we can do the correct accounting in the arena. */
chunkUnmapSpare(chunk);
vmChunkDestroy(chunk);
vmArena->contracted(arena, base, size);
}
}
{ {
Size vmem0 = trace->preTraceArenaReserved; Size vmem0 = trace->preTraceArenaReserved;

View file

@ -146,31 +146,26 @@ Bool BufferCheck(Buffer buffer)
* *
* See <code/mpmst.h> for structure definitions. */ * See <code/mpmst.h> for structure definitions. */
Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream) Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
char abzMode[5];
if (!TESTT(Buffer, buffer)) return ResFAIL; if (!TESTT(Buffer, buffer)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
abzMode[0] = (char)( (buffer->mode & BufferModeTRANSITION) ? 't' : '_' ); res = WriteF(stream, depth,
abzMode[1] = (char)( (buffer->mode & BufferModeLOGGED) ? 'l' : '_' );
abzMode[2] = (char)( (buffer->mode & BufferModeFLIPPED) ? 'f' : '_' );
abzMode[3] = (char)( (buffer->mode & BufferModeATTACHED) ? 'a' : '_' );
abzMode[4] = '\0';
res = WriteF(stream,
"Buffer $P ($U) {\n", "Buffer $P ($U) {\n",
(WriteFP)buffer, (WriteFU)buffer->serial, (WriteFP)buffer, (WriteFU)buffer->serial,
" class $P (\"$S\")\n", " class $P (\"$S\")\n",
(WriteFP)buffer->class, buffer->class->name, (WriteFP)buffer->class, buffer->class->name,
" Arena $P\n", (WriteFP)buffer->arena, " Arena $P\n", (WriteFP)buffer->arena,
" Pool $P\n", (WriteFP)buffer->pool, " Pool $P\n", (WriteFP)buffer->pool,
buffer->isMutator ? " ", buffer->isMutator ? "Mutator" : "Internal", " Buffer\n",
" Mutator Buffer\n" : " Internal Buffer\n", " mode $C$C$C$C (TRANSITION, LOGGED, FLIPPED, ATTACHED)\n",
" mode $S (TRANSITION, LOGGED, FLIPPED, ATTACHED)\n", (WriteFC)((buffer->mode & BufferModeTRANSITION) ? 't' : '_'),
(WriteFS)abzMode, (WriteFC)((buffer->mode & BufferModeLOGGED) ? 'l' : '_'),
(WriteFC)((buffer->mode & BufferModeFLIPPED) ? 'f' : '_'),
(WriteFC)((buffer->mode & BufferModeATTACHED) ? 'a' : '_'),
" fillSize $UKb\n", (WriteFU)(buffer->fillSize / 1024), " fillSize $UKb\n", (WriteFU)(buffer->fillSize / 1024),
" emptySize $UKb\n", (WriteFU)(buffer->emptySize / 1024), " emptySize $UKb\n", (WriteFU)(buffer->emptySize / 1024),
" alignment $W\n", (WriteFW)buffer->alignment, " alignment $W\n", (WriteFW)buffer->alignment,
@ -183,10 +178,10 @@ Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = buffer->class->describe(buffer, stream); res = buffer->class->describe(buffer, stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, "} Buffer $P ($U)\n", res = WriteF(stream, depth, "} Buffer $P ($U)\n",
(WriteFP)buffer, (WriteFU)buffer->serial, (WriteFP)buffer, (WriteFU)buffer->serial,
NULL); NULL);
return res; return res;
@ -1166,10 +1161,11 @@ static void bufferNoReassignSeg(Buffer buffer, Seg seg)
/* bufferTrivDescribe -- basic Buffer describe method */ /* bufferTrivDescribe -- basic Buffer describe method */
static Res bufferTrivDescribe(Buffer buffer, mps_lib_FILE *stream) static Res bufferTrivDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth)
{ {
if (!TESTT(Buffer, buffer)) return ResFAIL; if (!TESTT(Buffer, buffer)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
UNUSED(depth);
/* dispatching function does it all */ /* dispatching function does it all */
return ResOK; return ResOK;
} }
@ -1424,7 +1420,7 @@ static void segBufReassignSeg (Buffer buffer, Seg seg)
/* segBufDescribe -- describe method for SegBuf */ /* segBufDescribe -- describe method for SegBuf */
static Res segBufDescribe(Buffer buffer, mps_lib_FILE *stream) static Res segBufDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth)
{ {
SegBuf segbuf; SegBuf segbuf;
BufferClass super; BufferClass super;
@ -1437,10 +1433,10 @@ static Res segBufDescribe(Buffer buffer, mps_lib_FILE *stream)
/* Describe the superclass fields first via next-method call */ /* Describe the superclass fields first via next-method call */
super = BUFFER_SUPERCLASS(SegBufClass); super = BUFFER_SUPERCLASS(SegBufClass);
res = super->describe(buffer, stream); res = super->describe(buffer, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth,
"Seg $P\n", (WriteFP)segbuf->seg, "Seg $P\n", (WriteFP)segbuf->seg,
"rankSet $U\n", (WriteFU)segbuf->rankSet, "rankSet $U\n", (WriteFU)segbuf->rankSet,
NULL); NULL);

View file

@ -26,7 +26,6 @@ SRCID(cbs, "$Id$");
#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit) #define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit)
#define cbsLand(cbs) (&((cbs)->landStruct))
#define cbsOfLand(land) PARENT(CBSStruct, landStruct, land) #define cbsOfLand(land) PARENT(CBSStruct, landStruct, land)
#define cbsSplay(cbs) (&((cbs)->splayTreeStruct)) #define cbsSplay(cbs) (&((cbs)->splayTreeStruct))
#define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay) #define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay)
@ -36,9 +35,16 @@ SRCID(cbs, "$Id$");
PARENT(CBSFastBlockStruct, cbsBlockStruct, cbsBlockOfTree(_tree)) PARENT(CBSFastBlockStruct, cbsBlockStruct, cbsBlockOfTree(_tree))
#define cbsZonedBlockOfTree(_tree) \ #define cbsZonedBlockOfTree(_tree) \
PARENT(CBSZonedBlockStruct, cbsFastBlockStruct, cbsFastBlockOfTree(_tree)) PARENT(CBSZonedBlockStruct, cbsFastBlockStruct, cbsFastBlockOfTree(_tree))
#define cbsBlockKey(block) (&((block)->base))
#define cbsBlockPool(cbs) RVALUE((cbs)->blockPool) #define cbsBlockPool(cbs) RVALUE((cbs)->blockPool)
/* We pass the block base directly as a TreeKey (void *) assuming that
Addr can be encoded, and possibly breaking <design/type/#addr.use>.
On an exotic platform where this isn't true, pass the address of base.
i.e. add an & */
#define cbsBlockKey(block) ((TreeKey)(block)->base)
#define keyOfBaseVar(baseVar) ((TreeKey)(baseVar))
#define baseOfKey(key) ((Addr)(key))
/* CBSCheck -- Check CBS */ /* CBSCheck -- Check CBS */
@ -47,7 +53,7 @@ Bool CBSCheck(CBS cbs)
/* See .enter-leave.simple. */ /* See .enter-leave.simple. */
Land land; Land land;
CHECKS(CBS, cbs); CHECKS(CBS, cbs);
land = cbsLand(cbs); land = CBSLand(cbs);
CHECKD(Land, land); CHECKD(Land, land);
CHECKD(SplayTree, cbsSplay(cbs)); CHECKD(SplayTree, cbsSplay(cbs));
CHECKD(Pool, cbs->blockPool); CHECKD(Pool, cbs->blockPool);
@ -85,10 +91,11 @@ static Compare cbsCompare(Tree tree, TreeKey key)
Addr base1, base2, limit2; Addr base1, base2, limit2;
CBSBlock cbsBlock; CBSBlock cbsBlock;
AVER(tree != NULL); AVERT_CRITICAL(Tree, tree);
AVER(tree != TreeEMPTY); AVER_CRITICAL(tree != TreeEMPTY);
AVER_CRITICAL(key != NULL);
base1 = *(Addr *)key; base1 = baseOfKey(key);
cbsBlock = cbsBlockOfTree(tree); cbsBlock = cbsBlockOfTree(tree);
base2 = cbsBlock->base; base2 = cbsBlock->base;
limit2 = cbsBlock->limit; limit2 = cbsBlock->limit;
@ -118,7 +125,7 @@ static Bool cbsTestNode(SplayTree splay, Tree tree,
AVERT(Tree, tree); AVERT(Tree, tree);
AVER(closureP == NULL); AVER(closureP == NULL);
AVER(size > 0); AVER(size > 0);
AVER(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass)); AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsBlockOfTree(tree); block = cbsBlockOfTree(tree);
@ -134,7 +141,7 @@ static Bool cbsTestTree(SplayTree splay, Tree tree,
AVERT(Tree, tree); AVERT(Tree, tree);
AVER(closureP == NULL); AVER(closureP == NULL);
AVER(size > 0); AVER(size > 0);
AVER(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass)); AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsFastBlockOfTree(tree); block = cbsFastBlockOfTree(tree);
@ -150,7 +157,7 @@ static void cbsUpdateFastNode(SplayTree splay, Tree tree)
AVERT_CRITICAL(SplayTree, splay); AVERT_CRITICAL(SplayTree, splay);
AVERT_CRITICAL(Tree, tree); AVERT_CRITICAL(Tree, tree);
AVER_CRITICAL(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass)); AVER_CRITICAL(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
maxSize = CBSBlockSize(cbsBlockOfTree(tree)); maxSize = CBSBlockSize(cbsBlockOfTree(tree));
@ -181,13 +188,13 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree)
AVERT_CRITICAL(SplayTree, splay); AVERT_CRITICAL(SplayTree, splay);
AVERT_CRITICAL(Tree, tree); AVERT_CRITICAL(Tree, tree);
AVER_CRITICAL(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSZonedLandClass)); AVER_CRITICAL(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSZonedLandClass));
cbsUpdateFastNode(splay, tree); cbsUpdateFastNode(splay, tree);
zonedBlock = cbsZonedBlockOfTree(tree); zonedBlock = cbsZonedBlockOfTree(tree);
block = &zonedBlock->cbsFastBlockStruct.cbsBlockStruct; block = &zonedBlock->cbsFastBlockStruct.cbsBlockStruct;
arena = LandArena(cbsLand(cbsOfSplay(splay))); arena = LandArena(CBSLand(cbsOfSplay(splay)));
zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block)); zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block));
if (TreeHasLeft(tree)) if (TreeHasLeft(tree))
@ -450,7 +457,7 @@ static Res cbsInsert(Range rangeReturn, Land land, Range range)
limit = RangeLimit(range); limit = RangeLimit(range);
METER_ACC(cbs->treeSearch, cbs->treeSize); METER_ACC(cbs->treeSearch, cbs->treeSize);
b = SplayTreeNeighbours(&leftSplay, &rightSplay, cbsSplay(cbs), &base); b = SplayTreeNeighbours(&leftSplay, &rightSplay, cbsSplay(cbs), keyOfBaseVar(base));
if (!b) { if (!b) {
res = ResFAIL; res = ResFAIL;
goto fail; goto fail;
@ -553,7 +560,7 @@ static Res cbsDelete(Range rangeReturn, Land land, Range range)
limit = RangeLimit(range); limit = RangeLimit(range);
METER_ACC(cbs->treeSearch, cbs->treeSize); METER_ACC(cbs->treeSearch, cbs->treeSize);
if (!SplayTreeFind(&tree, cbsSplay(cbs), (void *)&base)) { if (!SplayTreeFind(&tree, cbsSplay(cbs), keyOfBaseVar(base))) {
res = ResFAIL; res = ResFAIL;
goto failSplayTreeSearch; goto failSplayTreeSearch;
} }
@ -619,7 +626,7 @@ static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, 0,
"[$P,$P)", "[$P,$P)",
(WriteFP)block->base, (WriteFP)block->base,
(WriteFP)block->limit, (WriteFP)block->limit,
@ -647,7 +654,7 @@ static Res cbsFastBlockDescribe(CBSFastBlock block, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, 0,
"[$P,$P) {$U}", "[$P,$P) {$U}",
(WriteFP)block->cbsBlockStruct.base, (WriteFP)block->cbsBlockStruct.base,
(WriteFP)block->cbsBlockStruct.limit, (WriteFP)block->cbsBlockStruct.limit,
@ -676,7 +683,7 @@ static Res cbsZonedBlockDescribe(CBSZonedBlock block, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, 0,
"[$P,$P) {$U, $B}", "[$P,$P) {$U, $B}",
(WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.base, (WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.base,
(WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.limit, (WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.limit,
@ -832,7 +839,7 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn,
AVERT(Land, land); AVERT(Land, land);
cbs = cbsOfLand(land); cbs = cbsOfLand(land);
AVERT(CBS, cbs); AVERT(CBS, cbs);
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); AVER(IsLandSubclass(CBSLand(cbs), CBSFastLandClass));
AVER(rangeReturn != NULL); AVER(rangeReturn != NULL);
AVER(oldRangeReturn != NULL); AVER(oldRangeReturn != NULL);
@ -917,7 +924,7 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn,
AVERT(Land, land); AVERT(Land, land);
cbs = cbsOfLand(land); cbs = cbsOfLand(land);
AVERT(CBS, cbs); AVERT(CBS, cbs);
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); AVER(IsLandSubclass(CBSLand(cbs), CBSFastLandClass));
AVER(rangeReturn != NULL); AVER(rangeReturn != NULL);
AVER(oldRangeReturn != NULL); AVER(oldRangeReturn != NULL);
@ -954,7 +961,7 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn,
AVERT(Land, land); AVERT(Land, land);
cbs = cbsOfLand(land); cbs = cbsOfLand(land);
AVERT(CBS, cbs); AVERT(CBS, cbs);
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass)); AVER(IsLandSubclass(CBSLand(cbs), CBSFastLandClass));
AVER(rangeReturn != NULL); AVER(rangeReturn != NULL);
AVER(oldRangeReturn != NULL); AVER(oldRangeReturn != NULL);
@ -1005,7 +1012,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
AVERT(Land, land); AVERT(Land, land);
cbs = cbsOfLand(land); cbs = cbsOfLand(land);
AVERT(CBS, cbs); AVERT(CBS, cbs);
AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass)); AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass));
/* AVERT(ZoneSet, zoneSet); */ /* AVERT(ZoneSet, zoneSet); */
AVER(BoolCheck(high)); AVER(BoolCheck(high));
@ -1065,7 +1072,7 @@ fail:
* See <design/land/#function.describe>. * See <design/land/#function.describe>.
*/ */
static Res cbsDescribe(Land land, mps_lib_FILE *stream) static Res cbsDescribe(Land land, mps_lib_FILE *stream, Count depth)
{ {
CBS cbs; CBS cbs;
Res res; Res res;
@ -1079,7 +1086,7 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"CBS $P {\n", (WriteFP)cbs, "CBS $P {\n", (WriteFP)cbs,
" blockPool: $P\n", (WriteFP)cbsBlockPool(cbs), " blockPool: $P\n", (WriteFP)cbsBlockPool(cbs),
" ownPool: $U\n", (WriteFU)cbs->ownPool, " ownPool: $U\n", (WriteFU)cbs->ownPool,
@ -1087,6 +1094,8 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
METER_WRITE(cbs->treeSearch, stream, depth + 2);
if (IsLandSubclass(land, CBSZonedLandClass)) if (IsLandSubclass(land, CBSZonedLandClass))
describe = cbsZonedSplayNodeDescribe; describe = cbsZonedSplayNodeDescribe;
else if (IsLandSubclass(land, CBSFastLandClass)) else if (IsLandSubclass(land, CBSFastLandClass))
@ -1094,12 +1103,12 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream)
else else
describe = cbsSplayNodeDescribe; describe = cbsSplayNodeDescribe;
res = SplayTreeDescribe(cbsSplay(cbs), stream, describe); res = SplayTreeDescribe(cbsSplay(cbs), stream, depth + 2, describe);
if (res != ResOK) return res; if (res != ResOK) return res;
METER_WRITE(cbs->treeSearch, stream); res = WriteF(stream, depth, "} CBS $P\n", (WriteFP)cbs, NULL);
res = WriteF(stream, "}\n", NULL); res = WriteF(stream, 0, "}\n", NULL);
return res; return res;
} }

View file

@ -37,6 +37,7 @@ typedef struct CBSZonedBlockStruct {
typedef struct CBSStruct *CBS; typedef struct CBSStruct *CBS;
extern Bool CBSCheck(CBS cbs); extern Bool CBSCheck(CBS cbs);
#define CBSLand(cbs) (&(cbs)->landStruct)
extern LandClass CBSLandClassGet(void); extern LandClass CBSLandClassGet(void);
extern LandClass CBSFastLandClassGet(void); extern LandClass CBSFastLandClassGet(void);

View file

@ -73,6 +73,8 @@ typedef struct mps_chain_s {
} ChainStruct; } ChainStruct;
extern Res GenDescDescribe(GenDesc gen, mps_lib_FILE *stream, Count depth);
extern Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount, extern Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
GenParamStruct *params); GenParamStruct *params);
extern void ChainDestroy(Chain chain); extern void ChainDestroy(Chain chain);
@ -84,6 +86,7 @@ extern void ChainStartGC(Chain chain, Trace trace);
extern void ChainEndGC(Chain chain, Trace trace); extern void ChainEndGC(Chain chain, Trace trace);
extern size_t ChainGens(Chain chain); extern size_t ChainGens(Chain chain);
extern GenDesc ChainGen(Chain chain, Index gen); extern GenDesc ChainGen(Chain chain, Index gen);
extern Res ChainDescribe(Chain chain, mps_lib_FILE *stream, Count depth);
extern Bool PoolGenCheck(PoolGen pgen); extern Bool PoolGenCheck(PoolGen pgen);
extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool); extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool);
@ -99,6 +102,7 @@ extern void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred
extern void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize); extern void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize);
extern void PoolGenAccountForSegSplit(PoolGen pgen); extern void PoolGenAccountForSegSplit(PoolGen pgen);
extern void PoolGenAccountForSegMerge(PoolGen pgen); extern void PoolGenAccountForSegMerge(PoolGen pgen);
extern Res PoolGenDescribe(PoolGen gen, mps_lib_FILE *stream, Count depth);
#endif /* chain_h */ #endif /* chain_h */

View file

@ -65,8 +65,8 @@ typedef union EventClockUnion {
(*(EventClockUnion *)&(clock)).half.high, \ (*(EventClockUnion *)&(clock)).half.high, \
(*(EventClockUnion *)&(clock)).half.low) (*(EventClockUnion *)&(clock)).half.low)
#define EVENT_CLOCK_WRITE(stream, clock) \ #define EVENT_CLOCK_WRITE(stream, depth, clock) \
WriteF(stream, "$W$W", \ WriteF(stream, depth, "$W$W", \
(*(EventClockUnion *)&(clock)).half.high, \ (*(EventClockUnion *)&(clock)).half.high, \
(*(EventClockUnion *)&(clock)).half.low, \ (*(EventClockUnion *)&(clock)).half.low, \
NULL) NULL)
@ -85,8 +85,8 @@ typedef union EventClockUnion {
#endif #endif
#define EVENT_CLOCK_WRITE(stream, clock) \ #define EVENT_CLOCK_WRITE(stream, depth, clock) \
WriteF(stream, "$W", (WriteFW)(clock), NULL) WriteF(stream, depth, "$W", (WriteFW)(clock), NULL)
#endif #endif
@ -135,8 +135,8 @@ __extension__ typedef unsigned long long EventClock;
(unsigned long)((clock) >> 32), \ (unsigned long)((clock) >> 32), \
(unsigned long)((clock) & 0xffffffff)) (unsigned long)((clock) & 0xffffffff))
#define EVENT_CLOCK_WRITE(stream, clock) \ #define EVENT_CLOCK_WRITE(stream, depth, clock) \
WriteF(stream, "$W$W", (WriteFW)((clock) >> 32), (WriteFW)clock, NULL) WriteF(stream, depth, "$W$W", (WriteFW)((clock) >> 32), (WriteFW)clock, NULL)
#endif /* Intel, GCC or Clang */ #endif /* Intel, GCC or Clang */
@ -153,8 +153,8 @@ typedef mps_clock_t EventClock;
#define EVENT_CLOCK_PRINT(stream, clock) \ #define EVENT_CLOCK_PRINT(stream, clock) \
fprintf(stream, "%lu", (unsigned long)clock) fprintf(stream, "%lu", (unsigned long)clock)
#define EVENT_CLOCK_WRITE(stream, clock) \ #define EVENT_CLOCK_WRITE(stream, depth, clock) \
WriteF(stream, "$W", (WriteFW)clock, NULL) WriteF(stream, depth, "$W", (WriteFW)clock, NULL)
#endif #endif

View file

@ -378,6 +378,7 @@
#define MVFF_SLOT_HIGH_DEFAULT FALSE #define MVFF_SLOT_HIGH_DEFAULT FALSE
#define MVFF_ARENA_HIGH_DEFAULT FALSE #define MVFF_ARENA_HIGH_DEFAULT FALSE
#define MVFF_FIRST_FIT_DEFAULT TRUE #define MVFF_FIRST_FIT_DEFAULT TRUE
#define MVFF_SPARE_DEFAULT 0.75
/* Pool MVT Configuration -- see <code/poolmv2.c> */ /* Pool MVT Configuration -- see <code/poolmv2.c> */

View file

@ -319,7 +319,7 @@ void EventLabelAddr(Addr addr, EventStringId id)
" $U", (WriteFU)event->name.f##index, " $U", (WriteFU)event->name.f##index,
Res EventDescribe(Event event, mps_lib_FILE *stream) Res EventDescribe(Event event, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
@ -329,14 +329,14 @@ Res EventDescribe(Event event, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Event $P {\n", (WriteFP)event, "Event $P {\n", (WriteFP)event,
" code $U\n", (WriteFU)event->any.code, " code $U\n", (WriteFU)event->any.code,
" clock ", NULL); " clock ", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = EVENT_CLOCK_WRITE(stream, event->any.clock); res = EVENT_CLOCK_WRITE(stream, depth, event->any.clock);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, "\n size $U\n", (WriteFU)event->any.size, NULL); res = WriteF(stream, depth, "\n size $U\n", (WriteFU)event->any.size, NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
switch (event->any.code) { switch (event->any.code) {
@ -347,7 +347,7 @@ Res EventDescribe(Event event, mps_lib_FILE *stream)
#define EVENT_DESC(X, name, _code, always, kind) \ #define EVENT_DESC(X, name, _code, always, kind) \
case _code: \ case _code: \
res = WriteF(stream, \ res = WriteF(stream, depth, \
" event \"$S\"", (WriteFS)#name, \ " event \"$S\"", (WriteFS)#name, \
EVENT_##name##_PARAMS(EVENT_DESC_PARAM, name) \ EVENT_##name##_PARAMS(EVENT_DESC_PARAM, name) \
NULL); \ NULL); \
@ -357,13 +357,13 @@ Res EventDescribe(Event event, mps_lib_FILE *stream)
EVENT_LIST(EVENT_DESC, X) EVENT_LIST(EVENT_DESC, X)
default: default:
res = WriteF(stream, " event type unknown", NULL); res = WriteF(stream, depth, " event type unknown", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
/* TODO: Hexdump unknown event contents. */ /* TODO: Hexdump unknown event contents. */
break; break;
} }
res = WriteF(stream, res = WriteF(stream, depth,
"\n} Event $P\n", (WriteFP)event, "\n} Event $P\n", (WriteFP)event,
NULL); NULL);
return res; return res;
@ -377,7 +377,7 @@ Res EventWrite(Event event, mps_lib_FILE *stream)
if (event == NULL) return ResFAIL; if (event == NULL) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = EVENT_CLOCK_WRITE(stream, event->any.clock); res = EVENT_CLOCK_WRITE(stream, 0, event->any.clock);
if (res != ResOK) if (res != ResOK)
return res; return res;
@ -388,7 +388,7 @@ Res EventWrite(Event event, mps_lib_FILE *stream)
#define EVENT_WRITE(X, name, code, always, kind) \ #define EVENT_WRITE(X, name, code, always, kind) \
case code: \ case code: \
res = WriteF(stream, " $S", #name, \ res = WriteF(stream, 0, " $S", #name, \
EVENT_##name##_PARAMS(EVENT_WRITE_PARAM, name) \ EVENT_##name##_PARAMS(EVENT_WRITE_PARAM, name) \
NULL); \ NULL); \
if (res != ResOK) return res; \ if (res != ResOK) return res; \
@ -396,7 +396,7 @@ Res EventWrite(Event event, mps_lib_FILE *stream)
EVENT_LIST(EVENT_WRITE, X) EVENT_LIST(EVENT_WRITE, X)
default: default:
res = WriteF(stream, " <unknown code $U>", event->any.code, NULL); res = WriteF(stream, 0, " <unknown code $U>", event->any.code, NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
/* TODO: Hexdump unknown event contents. */ /* TODO: Hexdump unknown event contents. */
break; break;
@ -416,7 +416,7 @@ void EventDump(mps_lib_FILE *stream)
/* This can happen if there's a backtrace very early in the life of /* This can happen if there's a backtrace very early in the life of
the MPS, and will cause an access violation if we continue. */ the MPS, and will cause an access violation if we continue. */
if (!eventInited) { if (!eventInited) {
(void)WriteF(stream, "No events\n", NULL); (void)WriteF(stream, 0, "No events\n", NULL);
return; return;
} }
@ -427,7 +427,7 @@ void EventDump(mps_lib_FILE *stream)
/* Try to keep going even if there's an error, because this is used as a /* Try to keep going even if there's an error, because this is used as a
backtrace and we'll take what we can get. */ backtrace and we'll take what we can get. */
(void)EventWrite(event, stream); (void)EventWrite(event, stream);
(void)WriteF(stream, "\n", NULL); (void)WriteF(stream, 0, "\n", NULL);
} }
} }
} }
@ -490,10 +490,11 @@ void EventLabelAddr(Addr addr, Word id)
} }
Res EventDescribe(Event event, mps_lib_FILE *stream) Res EventDescribe(Event event, mps_lib_FILE *stream, Count depth)
{ {
UNUSED(event); UNUSED(event);
UNUSED(stream); UNUSED(stream);
UNUSED(depth);
return ResUNIMPL; return ResUNIMPL;
} }

View file

@ -33,7 +33,7 @@ extern EventStringId EventInternString(const char *label);
extern EventStringId EventInternGenString(size_t, const char *label); extern EventStringId EventInternGenString(size_t, const char *label);
extern void EventLabelAddr(Addr addr, Word id); extern void EventLabelAddr(Addr addr, Word id);
extern void EventFlush(EventKind kind); extern void EventFlush(EventKind kind);
extern Res EventDescribe(Event event, mps_lib_FILE *stream); extern Res EventDescribe(Event event, mps_lib_FILE *stream, Count depth);
extern Res EventWrite(Event event, mps_lib_FILE *stream); extern Res EventWrite(Event event, mps_lib_FILE *stream);
extern void EventDump(mps_lib_FILE *stream); extern void EventDump(mps_lib_FILE *stream);

View file

@ -276,7 +276,7 @@ static Bool failoverFindInZones(Bool *foundReturn, Range rangeReturn, Range oldR
} }
static Res failoverDescribe(Land land, mps_lib_FILE *stream) static Res failoverDescribe(Land land, mps_lib_FILE *stream, Count depth)
{ {
Failover fo; Failover fo;
Res res; Res res;
@ -286,7 +286,7 @@ static Res failoverDescribe(Land land, mps_lib_FILE *stream)
if (!TESTT(Failover, fo)) return ResFAIL; if (!TESTT(Failover, fo)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Failover $P {\n", (WriteFP)fo, "Failover $P {\n", (WriteFP)fo,
" primary = $P ($S)\n", (WriteFP)fo->primary, " primary = $P ($S)\n", (WriteFP)fo->primary,
fo->primary->class->name, fo->primary->class->name,

View file

@ -13,6 +13,8 @@
typedef struct FailoverStruct *Failover; typedef struct FailoverStruct *Failover;
#define FailoverLand(fo) (&(fo)->landStruct)
extern Bool FailoverCheck(Failover failover); extern Bool FailoverCheck(Failover failover);
extern LandClass FailoverLandClassGet(void); extern LandClass FailoverLandClassGet(void);

View file

@ -38,7 +38,7 @@ SRCID(fbmtest, "$Id$");
static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried, static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried,
NDeallocateSucceeded; NDeallocateSucceeded;
static int verbose = 0; static Bool verbose = FALSE;
typedef unsigned FBMType; typedef unsigned FBMType;
enum { enum {
@ -80,10 +80,12 @@ static Index (indexOfAddr)(FBMState state, Addr a)
static void describe(FBMState state) { static void describe(FBMState state) {
switch (state->type) { switch (state->type) {
case FBMTypeCBS: case FBMTypeCBS:
die(CBSDescribe(state->the.cbs, mps_lib_get_stdout()), "CBSDescribe"); die(CBSDescribe(state->the.cbs, mps_lib_get_stdout(), 0),
"CBSDescribe");
break; break;
case FBMTypeFreelist: case FBMTypeFreelist:
die(FreelistDescribe(state->the.fl, mps_lib_get_stdout()), "FreelistDescribe"); die(FreelistDescribe(state->the.fl, mps_lib_get_stdout(), 0),
"FreelistDescribe");
break; break;
default: default:
cdie(0, "invalid state->type"); cdie(0, "invalid state->type");
@ -542,6 +544,8 @@ static void test(FBMState state, unsigned n) {
} }
if ((i + 1) % 1000 == 0) if ((i + 1) % 1000 == 0)
check(state); check(state);
if (i == 100)
describe(state);
} }
} }

View file

@ -18,14 +18,15 @@
* This code was created by first copying <code/weakcv.c> * This code was created by first copying <code/weakcv.c>
*/ */
#include "testlib.h"
#include "mpslib.h"
#include "mps.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "fmtdy.h" #include "fmtdy.h"
#include "fmtdytst.h" #include "fmtdytst.h"
#include "mpm.h"
#include "mps.h"
#include "mpsavm.h"
#include "mpscamc.h"
#include "mpslib.h"
#include "mpstd.h" #include "mpstd.h"
#include "testlib.h"
#include <stdio.h> /* printf */ #include <stdio.h> /* printf */
@ -141,6 +142,8 @@ static void *test(void *arg, size_t s)
} }
p = NULL; p = NULL;
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
mps_message_type_enable(arena, mps_message_type_finalization()); mps_message_type_enable(arena, mps_message_type_finalization());
/* <design/poolmrg/#test.promise.ut.churn> */ /* <design/poolmrg/#test.promise.ut.churn> */

View file

@ -147,7 +147,7 @@ static mps_addr_t test_awl_find_dependent(mps_addr_t addr)
static void *root[rootCOUNT]; static void *root[rootCOUNT];
static void test_trees(int mode, const char *name, mps_arena_t arena, static void test_trees(int mode, const char *name, mps_arena_t arena,
mps_ap_t ap, mps_pool_t pool, mps_ap_t ap,
mps_word_t (*make)(mps_word_t, mps_ap_t), mps_word_t (*make)(mps_word_t, mps_ap_t),
void (*reg)(mps_word_t, mps_arena_t)) void (*reg)(mps_word_t, mps_arena_t))
{ {
@ -158,7 +158,9 @@ static void test_trees(int mode, const char *name, mps_arena_t arena,
object_count = 0; object_count = 0;
printf("Making some %s finalized trees of objects.\n", name); printf("---- Mode %s, pool class %s, %s trees ----\n",
mode == ModePARK ? "PARK" : "POLL",
pool->class->name, name);
mps_arena_park(arena); mps_arena_park(arena);
/* make some trees */ /* 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); (*reg)((mps_word_t)root[i], arena);
} }
printf("Losing all pointers to the trees.\n");
/* clean out the roots */ /* clean out the roots */
for(i = 0; i < rootCOUNT; ++i) { for(i = 0; i < rootCOUNT; ++i) {
root[i] = 0; root[i] = 0;
@ -190,9 +191,15 @@ static void test_trees(int mode, const char *name, mps_arena_t arena,
object_alloc = 0; object_alloc = 0;
while (object_alloc < 1000 && !mps_message_poll(arena)) while (object_alloc < 1000 && !mps_message_poll(arena))
(void)DYLAN_INT(object_alloc++); (void)DYLAN_INT(object_alloc++);
printf(" Done.\n");
break; break;
} }
++ collections; ++ 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)) { while (mps_message_poll(arena)) {
mps_message_t message; mps_message_t message;
mps_addr_t objaddr; 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"); "root_create\n");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_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); 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); register_indirect_tree);
mps_ap_destroy(ap); mps_ap_destroy(ap);

View file

@ -193,11 +193,11 @@ Arena FormatArena(Format format)
/* FormatDescribe -- describe a format */ /* FormatDescribe -- describe a format */
Res FormatDescribe(Format format, mps_lib_FILE *stream) Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
res = WriteF(stream, res = WriteF(stream, depth,
"Format $P ($U) {\n", (WriteFP)format, (WriteFU)format->serial, "Format $P ($U) {\n", (WriteFP)format, (WriteFU)format->serial,
" arena $P ($U)\n", " arena $P ($U)\n",
(WriteFP)format->arena, (WriteFU)format->arena->serial, (WriteFP)format->arena, (WriteFU)format->arena->serial,

View file

@ -14,7 +14,7 @@ SRCID(freelist, "$Id$");
#define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land) #define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land)
#define freelistAlignment(fl) LandAlignment(&(fl)->landStruct) #define freelistAlignment(fl) LandAlignment(FreelistLand(fl))
typedef union FreelistBlockUnion { typedef union FreelistBlockUnion {
@ -171,7 +171,7 @@ Bool FreelistCheck(Freelist fl)
{ {
Land land; Land land;
CHECKS(Freelist, fl); CHECKS(Freelist, fl);
land = &fl->landStruct; land = FreelistLand(fl);
CHECKD(Land, land); CHECKD(Land, land);
/* See <design/freelist/#impl.grain.align> */ /* See <design/freelist/#impl.grain.align> */
CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment)); CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment));
@ -748,13 +748,13 @@ static Bool freelistDescribeVisitor(Land land, Range range,
{ {
Res res; Res res;
mps_lib_FILE *stream = closureP; mps_lib_FILE *stream = closureP;
Count depth = closureS;
if (!TESTT(Land, land)) return FALSE; if (!TESTT(Land, land)) return FALSE;
if (!RangeCheck(range)) return FALSE; if (!RangeCheck(range)) return FALSE;
if (stream == NULL) return FALSE; if (stream == NULL) return FALSE;
if (closureS != UNUSED_SIZE) return FALSE;
res = WriteF(stream, res = WriteF(stream, depth,
"[$P,", (WriteFP)RangeBase(range), "[$P,", (WriteFP)RangeBase(range),
"$P)", (WriteFP)RangeLimit(range), "$P)", (WriteFP)RangeLimit(range),
" {$U}\n", (WriteFU)RangeSize(range), " {$U}\n", (WriteFU)RangeSize(range),
@ -764,7 +764,7 @@ static Bool freelistDescribeVisitor(Land land, Range range,
} }
static Res freelistDescribe(Land land, mps_lib_FILE *stream) static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
{ {
Freelist fl; Freelist fl;
Res res; Res res;
@ -775,15 +775,15 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream)
if (!TESTT(Freelist, fl)) return ResFAIL; if (!TESTT(Freelist, fl)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Freelist $P {\n", (WriteFP)fl, "Freelist $P {\n", (WriteFP)fl,
" listSize = $U\n", (WriteFU)fl->listSize, " listSize = $U\n", (WriteFU)fl->listSize,
NULL); NULL);
b = LandIterate(land, freelistDescribeVisitor, stream, UNUSED_SIZE); b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
if (!b) return ResFAIL; if (!b) return ResFAIL;
res = WriteF(stream, "}\n", NULL); res = WriteF(stream, depth, "} Freelist $P\n", (WriteFP)fl, NULL);
return res; return res;
} }

View file

@ -13,6 +13,8 @@
typedef struct FreelistStruct *Freelist; typedef struct FreelistStruct *Freelist;
#define FreelistLand(fl) (&(fl)->landStruct)
extern Bool FreelistCheck(Freelist freelist); extern Bool FreelistCheck(Freelist freelist);
/* See <design/freelist/#impl.grain.align> */ /* See <design/freelist/#impl.grain.align> */

View file

@ -245,7 +245,8 @@ static void arena_setup(gcthread_fn_t fn,
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
watch(fn, name); watch(fn, name);
mps_arena_park(arena); mps_arena_park(arena);
printf("%u chunks\n", (unsigned)RingLength(&arena->chunkRing)); printf("%u chunks\n", (unsigned)TreeDebugCount(ArenaChunkTree(arena),
ChunkCompare, ChunkKey));
mps_pool_destroy(pool); mps_pool_destroy(pool);
mps_fmt_destroy(format); mps_fmt_destroy(format);
if (ngen > 0) if (ngen > 0)

View file

@ -1008,18 +1008,20 @@ Ref ArenaRead(Arena arena, Ref *p)
/* GlobalsDescribe -- describe the arena globals */ /* GlobalsDescribe -- describe the arena globals */
Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream) Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Arena arena; Arena arena;
Ring node, nextNode; Ring node, nextNode;
Index i; Index i;
TraceId ti;
Trace trace;
if (!TESTT(Globals, arenaGlobals)) return ResFAIL; if (!TESTT(Globals, arenaGlobals)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
arena = GlobalsArena(arenaGlobals); arena = GlobalsArena(arenaGlobals);
res = WriteF(stream, res = WriteF(stream, depth,
"mpsVersion $S\n", arenaGlobals->mpsVersionString, "mpsVersion $S\n", arenaGlobals->mpsVersionString,
"lock $P\n", (WriteFP)arenaGlobals->lock, "lock $P\n", (WriteFP)arenaGlobals->lock,
"pollThreshold $U kB\n", "pollThreshold $U kB\n",
@ -1043,25 +1045,22 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream)
arena->insideShield ? "inside shield\n" : "outside shield\n", arena->insideShield ? "inside shield\n" : "outside shield\n",
"busyTraces $B\n", (WriteFB)arena->busyTraces, "busyTraces $B\n", (WriteFB)arena->busyTraces,
"flippedTraces $B\n", (WriteFB)arena->flippedTraces, "flippedTraces $B\n", (WriteFB)arena->flippedTraces,
/* @@@@ no TraceDescribe function */
"epoch $U\n", (WriteFU)arena->epoch, "epoch $U\n", (WriteFU)arena->epoch,
"prehistory = $B\n", (WriteFB)arena->prehistory,
"history {\n",
" [note: indices are raw, not rotated]\n",
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
for(i=0; i < LDHistoryLENGTH; ++ i) { for(i=0; i < LDHistoryLENGTH; ++ i) {
res = WriteF(stream, res = WriteF(stream, depth + 2,
" history[$U] = $B\n", i, arena->history[i], "[$U] = $B\n", i, arena->history[i],
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, res = WriteF(stream, depth,
" [note: indices are raw, not rotated]\n" "} history\n",
" prehistory = $B\n", (WriteFB)arena->prehistory,
NULL);
if (res != ResOK) return res;
res = WriteF(stream,
"suspended $S\n", arena->suspended ? "YES" : "NO", "suspended $S\n", arena->suspended ? "YES" : "NO",
"shDepth $U\n", arena->shDepth, "shDepth $U\n", arena->shDepth,
"shCacheI $U\n", arena->shCacheI, "shCacheI $U\n", arena->shCacheI,
@ -1069,27 +1068,40 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = RootsDescribe(arenaGlobals, stream); res = RootsDescribe(arenaGlobals, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
RING_FOR(node, &arenaGlobals->poolRing, nextNode) { RING_FOR(node, &arenaGlobals->poolRing, nextNode) {
Pool pool = RING_ELT(Pool, arenaRing, node); Pool pool = RING_ELT(Pool, arenaRing, node);
res = PoolDescribe(pool, stream); res = PoolDescribe(pool, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
RING_FOR(node, &arena->formatRing, nextNode) { RING_FOR(node, &arena->formatRing, nextNode) {
Format format = RING_ELT(Format, arenaRing, node); Format format = RING_ELT(Format, arenaRing, node);
res = FormatDescribe(format, stream); res = FormatDescribe(format, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
RING_FOR(node, &arena->threadRing, nextNode) { RING_FOR(node, &arena->threadRing, nextNode) {
Thread thread = ThreadRingThread(node); Thread thread = ThreadRingThread(node);
res = ThreadDescribe(thread, stream); res = ThreadDescribe(thread, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
RING_FOR(node, &arena->chainRing, nextNode) {
Chain chain = RING_ELT(Chain, chainRing, node);
res = ChainDescribe(chain, stream, depth);
if (res != ResOK) return res;
}
TRACE_SET_ITER(ti, trace, TraceSetUNIV, arena)
if (TraceSetIsMember(arena->busyTraces, trace)) {
res = TraceDescribe(trace, stream, depth);
if (res != ResOK) return res;
}
TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena);
/* @@@@ What about grey rings? */ /* @@@@ What about grey rings? */
return res; return res;
} }

View file

@ -371,14 +371,14 @@ Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn,
* See <design/land/#function.describe> * See <design/land/#function.describe>
*/ */
Res LandDescribe(Land land, mps_lib_FILE *stream) Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
if (!TESTT(Land, land)) return ResFAIL; if (!TESTT(Land, land)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Land $P {\n", (WriteFP)land, "Land $P {\n", (WriteFP)land,
" class $P", (WriteFP)land->class, " class $P", (WriteFP)land->class,
" (\"$S\")\n", land->class->name, " (\"$S\")\n", land->class->name,
@ -389,11 +389,11 @@ Res LandDescribe(Land land, mps_lib_FILE *stream)
if (res != ResOK) if (res != ResOK)
return res; return res;
res = (*land->class->describe)(land, stream); res = (*land->class->describe)(land, stream, depth + 2);
if (res != ResOK) if (res != ResOK)
return res; return res;
res = WriteF(stream, "} Land $P\n", (WriteFP)land, NULL); res = WriteF(stream, depth, "} Land $P\n", (WriteFP)land, NULL);
return ResOK; return ResOK;
} }
@ -568,12 +568,13 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang
return ResUNIMPL; return ResUNIMPL;
} }
static Res landTrivDescribe(Land land, mps_lib_FILE *stream) static Res landTrivDescribe(Land land, mps_lib_FILE *stream, Count depth)
{ {
if (!TESTT(Land, land)) if (!TESTT(Land, land))
return ResFAIL; return ResFAIL;
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
UNUSED(depth);
/* dispatching function does it all */ /* dispatching function does it all */
return ResOK; return ResOK;
} }

View file

@ -71,7 +71,7 @@ static Index (indexOfAddr)(TestState state, Addr a)
static void describe(TestState state) { static void describe(TestState state) {
die(LandDescribe(state->land, mps_lib_get_stdout()), "LandDescribe"); die(LandDescribe(state->land, mps_lib_get_stdout(), 0), "LandDescribe");
} }
@ -486,10 +486,10 @@ extern int main(int argc, char *argv[])
CBSStruct cbsStruct; CBSStruct cbsStruct;
FreelistStruct flStruct; FreelistStruct flStruct;
FailoverStruct foStruct; FailoverStruct foStruct;
Land cbs = &cbsStruct.landStruct; Land cbs = CBSLand(&cbsStruct);
Land fl = &flStruct.landStruct; Land fl = FreelistLand(&flStruct);
Land fo = &foStruct.landStruct; Land fo = FailoverLand(&foStruct);
Pool mfs = &blockPool.poolStruct; Pool mfs = MFSPool(&blockPool);
Align align; Align align;
int i; int i;

View file

@ -126,6 +126,35 @@ static Size GenDescTotalSize(GenDesc gen)
} }
/* GenDescDescribe -- describe a generation in a chain */
Res GenDescDescribe(GenDesc gen, mps_lib_FILE *stream, Count depth)
{
Res res;
Ring node, nextNode;
if (!TESTT(GenDesc, gen)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = WriteF(stream, depth,
"GenDesc $P {\n", (WriteFP)gen,
" zones $B\n", (WriteFB)gen->zones,
" capacity $U\n", (WriteFU)gen->capacity,
" mortality $D\n", (WriteFD)gen->mortality,
NULL);
if (res != ResOK) return res;
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
res = PoolGenDescribe(pgen, stream, depth + 2);
if (res != ResOK) return res;
}
res = WriteF(stream, depth, "} GenDesc $P\n", (WriteFP)gen, NULL);
return res;
}
/* ChainCreate -- create a generation chain */ /* ChainCreate -- create a generation chain */
Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount, Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
@ -412,6 +441,35 @@ void ChainEndGC(Chain chain, Trace trace)
} }
/* ChainDescribe -- describe a chain */
Res ChainDescribe(Chain chain, mps_lib_FILE *stream, Count depth)
{
Res res;
size_t i;
if (!TESTT(Chain, chain)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = WriteF(stream, depth,
"Chain $P {\n", (WriteFP)chain,
" arena $P\n", (WriteFP)chain->arena,
" activeTraces $B\n", (WriteFB)chain->activeTraces,
NULL);
if (res != ResOK) return res;
for (i = 0; i < chain->genCount; ++i) {
res = GenDescDescribe(&chain->gens[i], stream, depth + 2);
if (res != ResOK) return res;
}
res = WriteF(stream, depth,
"} Chain $P\n", (WriteFP)chain,
NULL);
return res;
}
/* PoolGenInit -- initialize a PoolGen */ /* PoolGenInit -- initialize a PoolGen */
Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool) Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool)
@ -665,6 +723,33 @@ void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
} }
/* PoolGenDescribe -- describe a PoolGen */
Res PoolGenDescribe(PoolGen pgen, mps_lib_FILE *stream, Count depth)
{
Res res;
if (!TESTT(PoolGen, pgen)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = WriteF(stream, depth,
"PoolGen $P {\n", (WriteFP)pgen,
" pool $P ($U) \"$S\"\n",
(WriteFP)pgen->pool, (WriteFU)pgen->pool->serial,
(WriteFS)pgen->pool->class->name,
" segs $U\n", (WriteFU)pgen->segs,
" totalSize $U\n", (WriteFU)pgen->totalSize,
" freeSize $U\n", (WriteFU)pgen->freeSize,
" oldSize $U\n", (WriteFU)pgen->oldSize,
" oldDeferredSize $U\n", (WriteFU)pgen->oldDeferredSize,
" newSize $U\n", (WriteFU)pgen->newSize,
" newDeferredSize $U\n", (WriteFU)pgen->newDeferredSize,
"} PoolGen $P\n", (WriteFP)pgen,
NULL);
return res;
}
/* LocusInit -- initialize the locus module */ /* LocusInit -- initialize the locus module */
void LocusInit(Arena arena) void LocusInit(Arena arena)

View file

@ -64,12 +64,12 @@ void MeterAccumulate(Meter meter, Size amount)
/* MeterWrite -- describe method for meters */ /* MeterWrite -- describe method for meters */
Res MeterWrite(Meter meter, mps_lib_FILE *stream) Res MeterWrite(Meter meter, mps_lib_FILE *stream, Count depth)
{ {
Res res = ResOK; Res res = ResOK;
res = WriteF(stream, res = WriteF(stream, depth,
"meter $S {", meter->name, "meter \"$S\" {", meter->name,
"count: $U", meter->count, "count: $U", meter->count,
NULL); NULL);
if (res != ResOK) if (res != ResOK)
@ -77,7 +77,7 @@ Res MeterWrite(Meter meter, mps_lib_FILE *stream)
if (meter->count > 0) { if (meter->count > 0) {
double mean = meter->total / (double)meter->count; double mean = meter->total / (double)meter->count;
res = WriteF(stream, res = WriteF(stream, 0,
", total: $D", meter->total, ", total: $D", meter->total,
", max: $U", meter->max, ", max: $U", meter->max,
", min: $U", meter->min, ", min: $U", meter->min,
@ -87,7 +87,7 @@ Res MeterWrite(Meter meter, mps_lib_FILE *stream)
if (res != ResOK) if (res != ResOK)
return res; return res;
} }
res = WriteF(stream, "}\n", NULL); res = WriteF(stream, 0, "}\n", NULL);
return res; return res;
} }

View file

@ -35,7 +35,7 @@ typedef struct MeterStruct
extern void MeterInit(Meter meter, const char *name, void *owner); extern void MeterInit(Meter meter, const char *name, void *owner);
extern void MeterAccumulate(Meter meter, Size amount); extern void MeterAccumulate(Meter meter, Size amount);
extern Res MeterWrite(Meter meter, mps_lib_FILE *stream); extern Res MeterWrite(Meter meter, mps_lib_FILE *stream, Count depth);
extern void MeterEmit(Meter meter); extern void MeterEmit(Meter meter);
#define METER_DECL(meter) STATISTIC_DECL(struct MeterStruct meter) #define METER_DECL(meter) STATISTIC_DECL(struct MeterStruct meter)
@ -45,12 +45,12 @@ extern void MeterEmit(Meter meter);
#define METER_ACC(meter, delta) \ #define METER_ACC(meter, delta) \
STATISTIC(MeterAccumulate(&(meter), delta)) STATISTIC(MeterAccumulate(&(meter), delta))
#if defined(STATISTICS) #if defined(STATISTICS)
#define METER_WRITE(meter, stream) BEGIN \ #define METER_WRITE(meter, stream, depth) BEGIN \
Res _res = MeterWrite(&(meter), (stream)); \ Res _res = MeterWrite(&(meter), (stream), (depth)); \
if (_res != ResOK) return _res; \ if (_res != ResOK) return _res; \
END END
#elif defined(STATISTICS_NONE) #elif defined(STATISTICS_NONE)
#define METER_WRITE(meter, stream) NOOP #define METER_WRITE(meter, stream, depth) NOOP
#else #else
#error "No statistics configured." #error "No statistics configured."
#endif #endif

View file

@ -157,12 +157,11 @@ typedef const struct SrcIdStruct {
* Use these values for unused pointer, size closure arguments and * Use these values for unused pointer, size closure arguments and
* check them in the callback or visitor. * check them in the callback or visitor.
* *
* We use PointerAdd rather than a cast to avoid "warning C4306: 'type * Ensure that they have high bits set on 64-bit platforms for maximum
* cast' : conversion from 'unsigned int' to 'Pointer' of greater * unusability.
* size" on platform w3i6mv.
*/ */
#define UNUSED_POINTER PointerAdd(0, 0xB60405ED) /* PointeR UNUSED */ #define UNUSED_POINTER (Pointer)((Word)~0xFFFFFFFF | (Word)0xB60405ED) /* PointeR UNUSED */
#define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */ #define UNUSED_SIZE ((Size)~0xFFFFFFFF | (Size)0x520405ED) /* SiZe UNUSED */
/* PARENT -- parent structure /* PARENT -- parent structure

View file

@ -430,34 +430,35 @@ static Res WriteDouble(mps_lib_FILE *stream, double d)
* .writef.check: See .check.writef. * .writef.check: See .check.writef.
*/ */
Res WriteF(mps_lib_FILE *stream, ...) Res WriteF(mps_lib_FILE *stream, Count depth, ...)
{ {
Res res; Res res;
va_list args; va_list args;
va_start(args, stream); va_start(args, depth);
res = WriteF_v(stream, args); res = WriteF_v(stream, depth, args);
va_end(args); va_end(args);
return res; return res;
} }
Res WriteF_v(mps_lib_FILE *stream, va_list args) Res WriteF_v(mps_lib_FILE *stream, Count depth, va_list args)
{ {
const char *firstformat; const char *firstformat;
Res res; Res res;
firstformat = va_arg(args, const char *); firstformat = va_arg(args, const char *);
res = WriteF_firstformat_v(stream, firstformat, args); res = WriteF_firstformat_v(stream, depth, firstformat, args);
return res; return res;
} }
Res WriteF_firstformat_v(mps_lib_FILE *stream, Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth,
const char *firstformat, va_list args) const char *firstformat, va_list args)
{ {
const char *format; const char *format;
int r; int r;
size_t i; size_t i;
Res res; Res res;
Bool start_of_line = TRUE;
AVER(stream != NULL); AVER(stream != NULL);
@ -468,9 +469,18 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream,
break; break;
while(*format != '\0') { while(*format != '\0') {
if (start_of_line) {
for (i = 0; i < depth; ++i) {
mps_lib_fputc(' ', stream);
}
start_of_line = FALSE;
}
if (*format != '$') { if (*format != '$') {
r = mps_lib_fputc(*format, stream); /* Could be more efficient */ r = mps_lib_fputc(*format, stream); /* Could be more efficient */
if (r == mps_lib_EOF) return ResIO; if (r == mps_lib_EOF) return ResIO;
if (*format == '\n') {
start_of_line = TRUE;
}
} else { } else {
++format; ++format;
AVER(*format != '\0'); AVER(*format != '\0');
@ -493,7 +503,7 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream,
case 'F': { /* function */ case 'F': { /* function */
WriteFF f = va_arg(args, WriteFF); WriteFF f = va_arg(args, WriteFF);
Byte *b = (Byte *)&f; Byte *b = (Byte *)&f;
/* ISO C forbits casting function pointers to integer, so /* ISO C forbids casting function pointers to integer, so
decode bytes (see design.writef.f). decode bytes (see design.writef.f).
TODO: Be smarter about endianness. */ TODO: Be smarter about endianness. */
for(i=0; i < sizeof(WriteFF); i++) { for(i=0; i < sizeof(WriteFF); i++) {

View file

@ -156,9 +156,9 @@ extern Bool (WordIsP2)(Word word);
/* Formatted Output -- see <design/writef/>, <code/mpm.c> */ /* Formatted Output -- see <design/writef/>, <code/mpm.c> */
extern Res WriteF(mps_lib_FILE *stream, ...); extern Res WriteF(mps_lib_FILE *stream, Count depth, ...);
extern Res WriteF_v(mps_lib_FILE *stream, va_list args); extern Res WriteF_v(mps_lib_FILE *stream, Count depth, va_list args);
extern Res WriteF_firstformat_v(mps_lib_FILE *stream, extern Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth,
const char *firstformat, va_list args); const char *firstformat, va_list args);
@ -181,7 +181,7 @@ extern Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args);
extern void PoolFinish(Pool pool); extern void PoolFinish(Pool pool);
extern Bool PoolClassCheck(PoolClass class); extern Bool PoolClassCheck(PoolClass class);
extern Bool PoolCheck(Pool pool); extern Bool PoolCheck(Pool pool);
extern Res PoolDescribe(Pool pool, mps_lib_FILE *stream); extern Res PoolDescribe(Pool pool, mps_lib_FILE *stream, Count depth);
/* Must be thread-safe. See <design/interface-c/#thread-safety>. */ /* Must be thread-safe. See <design/interface-c/#thread-safety>. */
#define PoolArena(pool) ((pool)->arena) #define PoolArena(pool) ((pool)->arena)
@ -224,6 +224,9 @@ extern Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr);
extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
void *v, size_t s); void *v, size_t s);
extern void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); 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 Res PoolTrivInit(Pool pool, ArgList arg);
extern void PoolTrivFinish(Pool pool); extern void PoolTrivFinish(Pool pool);
extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size, extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size,
@ -242,7 +245,7 @@ extern void PoolNoBufferEmpty(Pool pool, Buffer buffer,
Addr init, Addr limit); Addr init, Addr limit);
extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer, extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer,
Addr init, Addr limit); Addr init, Addr limit);
extern Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream); extern Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream, Count depth);
extern Res PoolNoTraceBegin(Pool pool, Trace trace); extern Res PoolNoTraceBegin(Pool pool, Trace trace);
extern Res PoolTrivTraceBegin(Pool pool, Trace trace); extern Res PoolTrivTraceBegin(Pool pool, Trace trace);
extern Res PoolNoAccess(Pool pool, Seg seg, Addr addr, extern Res PoolNoAccess(Pool pool, Seg seg, Addr addr,
@ -277,6 +280,7 @@ extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsStepMethod step,
extern void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); extern void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p);
extern PoolDebugMixin PoolNoDebugMixin(Pool pool); extern PoolDebugMixin PoolNoDebugMixin(Pool pool);
extern BufferClass PoolNoBufferClass(void); extern BufferClass PoolNoBufferClass(void);
extern Size PoolNoSize(Pool pool);
#define ClassOfPool(pool) ((pool)->class) #define ClassOfPool(pool) ((pool)->class)
#define SuperclassOfPool(pool) \ #define SuperclassOfPool(pool) \
@ -398,6 +402,7 @@ extern void TraceSegAccess(Arena arena, Seg seg, AccessSet mode);
extern void TraceQuantum(Trace trace); extern void TraceQuantum(Trace trace);
extern Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why); extern Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why);
extern Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth);
/* traceanc.c -- Trace Ancillary */ /* traceanc.c -- Trace Ancillary */
@ -493,8 +498,8 @@ extern void ArenaDestroy(Arena arena);
extern Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, extern Res ArenaInit(Arena arena, ArenaClass class, Size grainSize,
ArgList args); ArgList args);
extern void ArenaFinish(Arena arena); extern void ArenaFinish(Arena arena);
extern Res ArenaDescribe(Arena arena, mps_lib_FILE *stream); extern Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth);
extern Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream); extern Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth);
extern Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context); extern Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context);
extern Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit); extern Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit);
extern void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit); extern void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit);
@ -505,7 +510,7 @@ extern Res GlobalsInit(Globals arena);
extern void GlobalsFinish(Globals arena); extern void GlobalsFinish(Globals arena);
extern Res GlobalsCompleteCreate(Globals arenaGlobals); extern Res GlobalsCompleteCreate(Globals arenaGlobals);
extern void GlobalsPrepareToDestroy(Globals arenaGlobals); extern void GlobalsPrepareToDestroy(Globals arenaGlobals);
extern Res GlobalsDescribe(Globals arena, mps_lib_FILE *stream); extern Res GlobalsDescribe(Globals arena, mps_lib_FILE *stream, Count depth);
extern Ring GlobalsRememberedSummaryRing(Globals); extern Ring GlobalsRememberedSummaryRing(Globals);
#define ArenaGlobals(arena) (&(arena)->globals) #define ArenaGlobals(arena) (&(arena)->globals)
@ -519,6 +524,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
#define ArenaGrainSize(arena) ((arena)->grainSize) #define ArenaGrainSize(arena) ((arena)->grainSize)
#define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank]) #define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank])
#define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing) #define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing)
#define ArenaChunkTree(arena) RVALUE((arena)->chunkTree)
extern Bool ArenaGrainSizeCheck(Size size); extern Bool ArenaGrainSizeCheck(Size size);
#define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena)) #define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena))
@ -558,6 +564,7 @@ extern Res ArenaStartCollect(Globals globals, int why);
extern Res ArenaCollect(Globals globals, int why); extern Res ArenaCollect(Globals globals, int why);
extern Bool ArenaHasAddr(Arena arena, Addr addr); extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr); extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
extern void ArenaSetEmergency(Arena arena, Bool emergency); extern void ArenaSetEmergency(Arena arena, Bool emergency);
extern Bool ArenaEmergency(Arena arean); extern Bool ArenaEmergency(Arena arean);
@ -567,7 +574,7 @@ extern void ControlFinish(Arena arena);
extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size, extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
Bool withReservoirPermit); Bool withReservoirPermit);
extern void ControlFree(Arena arena, void *base, size_t size); extern void ControlFree(Arena arena, void *base, size_t size);
extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream); extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth);
/* Peek/Poke /* Peek/Poke
@ -622,8 +629,6 @@ extern void ArenaCompact(Arena arena, Trace trace);
extern Res ArenaFinalize(Arena arena, Ref obj); extern Res ArenaFinalize(Arena arena, Ref obj);
extern Res ArenaDefinalize(Arena arena, Ref obj); extern Res ArenaDefinalize(Arena arena, Ref obj);
extern Bool ArenaIsReservedAddr(Arena arena, Addr addr);
#define ArenaReservoir(arena) (&(arena)->reservoirStruct) #define ArenaReservoir(arena) (&(arena)->reservoirStruct)
#define ReservoirPool(reservoir) (&(reservoir)->poolStruct) #define ReservoirPool(reservoir) (&(reservoir)->poolStruct)
@ -667,7 +672,6 @@ extern Bool SegOfAddr(Seg *segReturn, Arena arena, Addr addr);
extern Bool SegFirst(Seg *segReturn, Arena arena); extern Bool SegFirst(Seg *segReturn, Arena arena);
extern Bool SegNext(Seg *segReturn, Arena arena, Seg seg); extern Bool SegNext(Seg *segReturn, Arena arena, Seg seg);
extern Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next); extern Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next);
extern Bool SegFindAboveAddr(Seg *segReturn, Arena arena, Addr addr);
extern void SegSetWhite(Seg seg, TraceSet white); extern void SegSetWhite(Seg seg, TraceSet white);
extern void SegSetGrey(Seg seg, TraceSet grey); extern void SegSetGrey(Seg seg, TraceSet grey);
extern void SegSetRankSet(Seg seg, RankSet rankSet); extern void SegSetRankSet(Seg seg, RankSet rankSet);
@ -676,7 +680,7 @@ extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi,
Bool withReservoirPermit); Bool withReservoirPermit);
extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at, extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at,
Bool withReservoirPermit); Bool withReservoirPermit);
extern Res SegDescribe(Seg seg, mps_lib_FILE *stream); extern Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth);
extern void SegSetSummary(Seg seg, RefSet summary); extern void SegSetSummary(Seg seg, RefSet summary);
extern Buffer SegBuffer(Seg seg); extern Buffer SegBuffer(Seg seg);
extern void SegSetBuffer(Seg seg, Buffer buffer); extern void SegSetBuffer(Seg seg, Buffer buffer);
@ -735,7 +739,7 @@ extern Res BufferCreate(Buffer *bufferReturn, BufferClass class,
extern void BufferDestroy(Buffer buffer); extern void BufferDestroy(Buffer buffer);
extern Bool BufferCheck(Buffer buffer); extern Bool BufferCheck(Buffer buffer);
extern Bool SegBufCheck(SegBuf segbuf); extern Bool SegBufCheck(SegBuf segbuf);
extern Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream); extern Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth);
extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size, extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size,
Bool withReservoirPermit); Bool withReservoirPermit);
/* macro equivalent for BufferReserve, keep in sync with <code/buffer.c> */ /* macro equivalent for BufferReserve, keep in sync with <code/buffer.c> */
@ -834,7 +838,7 @@ extern Bool FormatCheck(Format format);
extern Res FormatCreate(Format *formatReturn, Arena arena, ArgList args); extern Res FormatCreate(Format *formatReturn, Arena arena, ArgList args);
extern void FormatDestroy(Format format); extern void FormatDestroy(Format format);
extern Arena FormatArena(Format format); extern Arena FormatArena(Format format);
extern Res FormatDescribe(Format format, mps_lib_FILE *stream); extern Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth);
/* Reference Interface -- see <code/ref.c> */ /* Reference Interface -- see <code/ref.c> */
@ -981,8 +985,8 @@ extern Res RootCreateFun(Root *rootReturn, Arena arena,
extern void RootDestroy(Root root); extern void RootDestroy(Root root);
extern Bool RootModeCheck(RootMode mode); extern Bool RootModeCheck(RootMode mode);
extern Bool RootCheck(Root root); extern Bool RootCheck(Root root);
extern Res RootDescribe(Root root, mps_lib_FILE *stream); extern Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth);
extern Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream); extern Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth);
extern Rank RootRank(Root root); extern Rank RootRank(Root root);
extern AccessSet RootPM(Root root); extern AccessSet RootPM(Root root);
extern RefSet RootSummary(Root root); extern RefSet RootSummary(Root root);
@ -1028,7 +1032,7 @@ extern Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Si
extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); extern Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
extern Res LandDescribe(Land land, mps_lib_FILE *stream); extern Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth);
extern Bool LandFlush(Land dest, Land src); extern Bool LandFlush(Land dest, Land src);
extern Size LandSlowSize(Land land); extern Size LandSlowSize(Land land);

View file

@ -5,14 +5,15 @@
* Portions copyright (C) 2002 Global Graphics Software. * Portions copyright (C) 2002 Global Graphics Software.
*/ */
#include "mpm.h"
#include "mps.h"
#include "mpsavm.h"
#include "mpscmfs.h"
#include "mpscmv.h" #include "mpscmv.h"
#include "mpscmvff.h" #include "mpscmvff.h"
#include "mpscmfs.h"
#include "mpslib.h" #include "mpslib.h"
#include "mpsavm.h" #include "mpslib.h"
#include "testlib.h" #include "testlib.h"
#include "mpslib.h"
#include "mps.h"
#include <stdio.h> /* printf */ #include <stdio.h> /* printf */
@ -23,9 +24,20 @@
#define testLOOPS 10 #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_size = mps_pool_total_size(pool);
size_t free_size = mps_pool_free_size(pool);
Insist(total_size - free_size == allocated);
}
/* stress -- create a pool of the requested type and allocate in it */ /* 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, const char *name, mps_class_t pool_class,
mps_arg_s *args) mps_arg_s *args)
{ {
@ -34,8 +46,10 @@ static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i),
size_t i, k; size_t i, k;
int *ps[testSetSIZE]; int *ps[testSetSIZE];
size_t ss[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); res = mps_pool_create_k(&pool, arena, pool_class, args);
if (res != MPS_RES_OK) if (res != MPS_RES_OK)
@ -48,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]); res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
if (res != MPS_RES_OK) if (res != MPS_RES_OK)
return res; return res;
allocated += alignUp(ss[i], align) + debugOverhead;
if (ss[i] >= sizeof(ps[i])) if (ss[i] >= sizeof(ps[i]))
*ps[i] = 1; /* Write something, so it gets swap. */ *ps[i] = 1; /* Write something, so it gets swap. */
check_allocated_size(pool, allocated);
} }
mps_pool_check_fenceposts(pool); mps_pool_check_fenceposts(pool);
@ -72,15 +88,20 @@ 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]); mps_free(pool, (mps_addr_t)ps[i], ss[i]);
/* if (i == testSetSIZE/2) */ /* if (i == testSetSIZE/2) */
/* PoolDescribe((Pool)pool, mps_lib_stdout); */ /* PoolDescribe((Pool)pool, mps_lib_stdout); */
Insist(alignUp(ss[i], align) + debugOverhead <= allocated);
allocated -= alignUp(ss[i], align) + debugOverhead;
} }
/* allocate some new objects */ /* allocate some new objects */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) { for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
ss[i] = (*size)(i); ss[i] = (*size)(i);
res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]); res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
if (res != MPS_RES_OK) return res; if (res != MPS_RES_OK) return res;
allocated += alignUp(ss[i], align) + debugOverhead;
} }
check_allocated_size(pool, allocated);
} }
die(PoolDescribe(pool, mps_lib_get_stdout(), 0), "PoolDescribe");
mps_pool_destroy(pool); mps_pool_destroy(pool);
return MPS_RES_OK; return MPS_RES_OK;
@ -150,8 +171,8 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
die(stress(arena, randomSize8, "MVFF", mps_class_mvff(), args), die(stress(arena, NULL, randomSize8, align, "MVFF",
"stress MVFF"); mps_class_mvff(), args), "stress MVFF");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
@ -161,31 +182,31 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, randomSize8, "MVFF debug", mps_class_mvff_debug(), args), die(stress(arena, options, randomSize8, align, "MVFF debug",
"stress MVFF debug"); mps_class_mvff_debug(), args), "stress MVFF debug");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6); mps_align_t align = (mps_align_t)1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, randomSize, "MV", mps_class_mv(), args), die(stress(arena, NULL, randomSize, align, "MV",
"stress MV"); mps_class_mv(), args), "stress MV");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6); mps_align_t align = (mps_align_t)1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align); MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, randomSize, "MV debug", mps_class_mv_debug(), args), die(stress(arena, options, randomSize, align, "MV debug",
"stress MV debug"); mps_class_mv_debug(), args), "stress MV debug");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
fixedSizeSize = 1 + rnd() % 64; fixedSizeSize = 1 + rnd() % 64;
MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize); MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize);
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 100000); MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 100000);
die(stress(arena, fixedSize, "MFS", mps_class_mfs(), args), die(stress(arena, NULL, fixedSize, MPS_PF_ALIGN, "MFS",
"stress MFS"); mps_class_mfs(), args), "stress MFS");
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
mps_arena_destroy(arena); mps_arena_destroy(arena);

View file

@ -81,6 +81,8 @@ typedef struct mps_class_s {
PoolBufferClassMethod bufferClass; /* default BufferClass of pool */ PoolBufferClassMethod bufferClass; /* default BufferClass of pool */
PoolDescribeMethod describe; /* describe the contents of the pool */ PoolDescribeMethod describe; /* describe the contents of the pool */
PoolDebugMixinMethod debugMixin; /* find the debug mixin, if any */ PoolDebugMixinMethod debugMixin; /* find the debug mixin, if any */
PoolSizeMethod totalSize; /* total memory allocated from arena */
PoolSizeMethod freeSize; /* free memory (unused by client program) */
Bool labelled; /* whether it has been EventLabelled */ Bool labelled; /* whether it has been EventLabelled */
Sig sig; /* .class.end-sig */ Sig sig; /* .class.end-sig */
} PoolClassStruct; } PoolClassStruct;
@ -136,6 +138,8 @@ typedef struct MFSStruct { /* MFS outer structure */
Bool extendSelf; /* whether to allocate tracts */ Bool extendSelf; /* whether to allocate tracts */
Size unitSize; /* rounded for management purposes */ Size unitSize; /* rounded for management purposes */
struct MFSHeaderStruct *freeList; /* head of the free list */ struct MFSHeaderStruct *freeList; /* head of the free list */
Size total; /* total size allocated from arena */
Size free; /* free space in pool */
Tract tractList; /* the first tract */ Tract tractList; /* the first tract */
Sig sig; /* <design/sig/> */ Sig sig; /* <design/sig/> */
} MFSStruct; } MFSStruct;
@ -158,7 +162,7 @@ typedef struct MVStruct { /* MV pool outer structure */
Size extendBy; /* segment size to extend pool by */ Size extendBy; /* segment size to extend pool by */
Size avgSize; /* client estimate of allocation size */ Size avgSize; /* client estimate of allocation size */
Size maxSize; /* client estimate of maximum size */ Size maxSize; /* client estimate of maximum size */
Size space; /* total free space in pool */ Size free; /* free space in pool */
Size lost; /* <design/poolmv/#lost> */ Size lost; /* <design/poolmv/#lost> */
RingStruct spans; /* span chain */ RingStruct spans; /* span chain */
Sig sig; /* <design/sig/> */ Sig sig; /* <design/sig/> */
@ -515,18 +519,6 @@ typedef struct TraceStruct {
} TraceStruct; } TraceStruct;
/* ChunkCacheEntryStruct -- cache entry in the chunk cache */
#define ChunkCacheEntrySig ((Sig)0x519C80CE) /* SIGnature CHUnk Cache Entry */
typedef struct ChunkCacheEntryStruct {
Sig sig;
Chunk chunk;
Addr base;
Addr limit;
} ChunkCacheEntryStruct;
/* ArenaClassStruct -- generic arena class interface */ /* ArenaClassStruct -- generic arena class interface */
#define ArenaClassSig ((Sig)0x519A6C1A) /* SIGnature ARena CLAss */ #define ArenaClassSig ((Sig)0x519A6C1A) /* SIGnature ARena CLAss */
@ -740,9 +732,9 @@ typedef struct mps_arena_s {
Addr lastTractBase; /* base address of lastTract */ Addr lastTractBase; /* base address of lastTract */
Chunk primary; /* the primary chunk */ Chunk primary; /* the primary chunk */
RingStruct chunkRing; /* all the chunks */ RingStruct chunkRing; /* all the chunks, in a ring for iteration */
Tree chunkTree; /* all the chunks, in a tree for fast lookup */
Serial chunkSerial; /* next chunk number */ Serial chunkSerial; /* next chunk number */
ChunkCacheEntryStruct chunkCache; /* just one entry */
Bool hasFreeLand; /* Is freeLand available? */ Bool hasFreeLand; /* Is freeLand available? */
MFSStruct freeCBSBlockPoolStruct; MFSStruct freeCBSBlockPoolStruct;

View file

@ -128,7 +128,7 @@ typedef void (*ArenaFreeMethod)(Addr base, Size size, Pool pool);
typedef Res (*ArenaChunkInitMethod)(Chunk chunk, BootBlock boot); typedef Res (*ArenaChunkInitMethod)(Chunk chunk, BootBlock boot);
typedef void (*ArenaChunkFinishMethod)(Chunk chunk); typedef void (*ArenaChunkFinishMethod)(Chunk chunk);
typedef void (*ArenaCompactMethod)(Arena arena, Trace trace); typedef void (*ArenaCompactMethod)(Arena arena, Trace trace);
typedef Res (*ArenaDescribeMethod)(Arena arena, mps_lib_FILE *stream); typedef Res (*ArenaDescribeMethod)(Arena arena, mps_lib_FILE *stream, Count depth);
typedef Res (*ArenaPagesMarkAllocatedMethod)(Arena arena, Chunk chunk, typedef Res (*ArenaPagesMarkAllocatedMethod)(Arena arena, Chunk chunk,
Index baseIndex, Count pages, Index baseIndex, Count pages,
Pool pool); Pool pool);
@ -168,7 +168,7 @@ typedef void (*SegSetRankSummaryMethod)(Seg seg, RankSet rankSet,
typedef void (*SegSetSummaryMethod)(Seg seg, RefSet summary); typedef void (*SegSetSummaryMethod)(Seg seg, RefSet summary);
typedef Buffer (*SegBufferMethod)(Seg seg); typedef Buffer (*SegBufferMethod)(Seg seg);
typedef void (*SegSetBufferMethod)(Seg seg, Buffer buffer); typedef void (*SegSetBufferMethod)(Seg seg, Buffer buffer);
typedef Res (*SegDescribeMethod)(Seg seg, mps_lib_FILE *stream); typedef Res (*SegDescribeMethod)(Seg seg, mps_lib_FILE *stream, Count depth);
typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, typedef Res (*SegMergeMethod)(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit, Addr base, Addr mid, Addr limit,
Bool withReservoirPermit); Bool withReservoirPermit);
@ -188,7 +188,7 @@ typedef Seg (*BufferSegMethod)(Buffer buffer);
typedef RankSet (*BufferRankSetMethod)(Buffer buffer); typedef RankSet (*BufferRankSetMethod)(Buffer buffer);
typedef void (*BufferSetRankSetMethod)(Buffer buffer, RankSet rankSet); typedef void (*BufferSetRankSetMethod)(Buffer buffer, RankSet rankSet);
typedef void (*BufferReassignSegMethod)(Buffer buffer, Seg seg); typedef void (*BufferReassignSegMethod)(Buffer buffer, Seg seg);
typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream); typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream, Count depth);
/* Pool*Method -- see <design/class-interface/> */ /* Pool*Method -- see <design/class-interface/> */
@ -235,8 +235,9 @@ typedef void (*PoolWalkMethod)(Pool pool, Seg seg,
void *v, size_t s); void *v, size_t s);
typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p); typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p);
typedef BufferClass (*PoolBufferClassMethod)(void); typedef BufferClass (*PoolBufferClassMethod)(void);
typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream); typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream, Count depth);
typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool); typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool);
typedef Size (*PoolSizeMethod)(Pool pool);
/* Messages /* Messages
@ -277,7 +278,7 @@ typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP
typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS); typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete); typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high); typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream); typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth);
/* CONSTANTS */ /* CONSTANTS */

View file

@ -188,6 +188,9 @@ extern const struct mps_key_s _mps_key_max_size;
extern const struct mps_key_s _mps_key_align; extern const struct mps_key_s _mps_key_align;
#define MPS_KEY_ALIGN (&_mps_key_align) #define MPS_KEY_ALIGN (&_mps_key_align)
#define MPS_KEY_ALIGN_FIELD align #define MPS_KEY_ALIGN_FIELD align
extern const struct mps_key_s _mps_key_spare;
#define MPS_KEY_SPARE (&_mps_key_spare)
#define MPS_KEY_SPARE_FIELD double
extern const struct mps_key_s _mps_key_interior; extern const struct mps_key_s _mps_key_interior;
#define MPS_KEY_INTERIOR (&_mps_key_interior) #define MPS_KEY_INTERIOR (&_mps_key_interior)
#define MPS_KEY_INTERIOR_FIELD b #define MPS_KEY_INTERIOR_FIELD b
@ -469,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, extern mps_res_t mps_pool_create_k(mps_pool_t *, mps_arena_t,
mps_class_t, mps_arg_s []); mps_class_t, mps_arg_s []);
extern void mps_pool_destroy(mps_pool_t); 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 <code/chain.h#gen-param>. */ /* .gen-param: This structure must match <code/chain.h#gen-param>. */
typedef struct mps_gen_param_s { typedef struct mps_gen_param_s {
@ -480,6 +488,9 @@ extern mps_res_t mps_chain_create(mps_chain_t *, mps_arena_t,
size_t, mps_gen_param_s *); size_t, mps_gen_param_s *);
extern void mps_chain_destroy(mps_chain_t); 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(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 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); extern void mps_free(mps_pool_t, mps_addr_t, size_t);

View file

@ -9,8 +9,9 @@
#include "mps.h" #include "mps.h"
extern size_t mps_mv_free_size(mps_pool_t mps_pool); #define mps_mv_free_size mps_pool_free_size
extern size_t mps_mv_size(mps_pool_t mps_pool); #define mps_mv_size mps_pool_total_size
extern mps_class_t mps_class_mv(void); extern mps_class_t mps_class_mv(void);
extern mps_class_t mps_class_mv_debug(void); extern mps_class_t mps_class_mv_debug(void);

View file

@ -1,27 +1,24 @@
/* mpscmv2.h: MEMORY POOL SYSTEM CLASS "MVT" /* mpscmv2.h: MEMORY POOL SYSTEM CLASS "MVT"
* *
* $Id$ * $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 #ifndef mpscmv2_h
#define mpscmv2_h #define mpscmv2_h
#include "mps.h" #include "mpscmvt.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);
#endif /* mpscmv2_h */ #endif /* mpscmv2_h */
/* C. COPYRIGHT AND LICENSE /* C. COPYRIGHT AND LICENSE
* *
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>. * Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact * All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options. * Ravenbrook for commercial licensing options.
* *

View file

@ -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 (&_mps_key_mvff_first_fit)
#define MPS_KEY_MVFF_FIRST_FIT_FIELD b #define MPS_KEY_MVFF_FIRST_FIT_FIELD b
extern size_t mps_mvff_free_size(mps_pool_t mps_pool); #define mps_mvff_free_size mps_pool_free_size
extern size_t mps_mvff_size(mps_pool_t mps_pool); #define mps_mvff_size mps_pool_total_size
extern mps_class_t mps_class_mvff(void); extern mps_class_t mps_class_mvff(void);
extern mps_class_t mps_class_mvff_debug(void); extern mps_class_t mps_class_mvff_debug(void);

View file

@ -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 (&_mps_key_mvt_frag_limit)
#define MPS_KEY_MVT_FRAG_LIMIT_FIELD d #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); extern mps_class_t mps_class_mvt(void);
/* The mvt pool class supports two extensions to the pool protocol: #define mps_mvt_free_size mps_pool_free_size
size and free_size. */ #define mps_mvt_size mps_pool_total_size
extern size_t mps_mvt_free_size(mps_pool_t mps_pool);
extern size_t mps_mvt_size(mps_pool_t mps_pool);
#endif /* mpscmvt_h */ #endif /* mpscmvt_h */

View file

@ -678,6 +678,40 @@ void mps_pool_destroy(mps_pool_t pool)
ArenaLeave(arena); 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) mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size)
{ {

View file

@ -4,18 +4,19 @@
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/ */
#include <stdio.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <time.h> #include <time.h>
#include "mpscmvt.h" #include "mpm.h"
#include "mps.h" #include "mps.h"
#include "mpslib.h"
#include "mpsavm.h" #include "mpsavm.h"
#include "mpscmvt.h"
#include "mpslib.h"
#include "mpstd.h"
#include "testlib.h" #include "testlib.h"
#include <math.h>
/* expdev() -- exponentially distributed random deviates /* expdev() -- exponentially distributed random deviates
* *
* From <http://cfatab.harvard.edu/nr/bookcpdf/c7-2.pdf> * From <http://cfatab.harvard.edu/nr/bookcpdf/c7-2.pdf>
@ -113,6 +114,9 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align,
printf("%"PRIwWORD PRIXLONGEST" %6"PRIXLONGEST" ", printf("%"PRIwWORD PRIXLONGEST" %6"PRIXLONGEST" ",
(ulongest_t)ps[i], (ulongest_t)ss[i]); (ulongest_t)ps[i], (ulongest_t)ss[i]);
} }
if (i == 100) {
PoolDescribe(pool, mps_lib_get_stdout(), 0);
}
} }
if (verbose) { if (verbose) {
putchar('\n'); putchar('\n');

View file

@ -403,7 +403,7 @@ Bool NailboardIsResRange(Nailboard board, Addr base, Addr limit)
} }
Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream) Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream, Count depth)
{ {
Index i, j; Index i, j;
Res res; Res res;
@ -413,35 +413,38 @@ Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream)
if (stream == NULL) if (stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth, "Nailboard $P {\n", (WriteFP)board, NULL);
"Nailboard $P\n{\n", (WriteFP)board, if (res != ResOK)
" base: $P\n", (WriteFP)RangeBase(&board->range), return res;
" limit: $P\n", (WriteFP)RangeLimit(&board->range),
res = RangeDescribe(&board->range, stream, depth + 2);
if (res != ResOK)
return res;
res = WriteF(stream, depth + 2,
"levels: $U\n", (WriteFU)board->levels, "levels: $U\n", (WriteFU)board->levels,
"newNails: $S\n", board->newNails ? "TRUE" : "FALSE", "newNails: $S\n", board->newNails ? "TRUE" : "FALSE",
"alignShift: $U\n", (WriteFU)board->alignShift, "alignShift: $U\n", (WriteFU)board->alignShift,
NULL); NULL);
if (res != ResOK)
return res;
for(i = 0; i < board->levels; ++i) { for(i = 0; i < board->levels; ++i) {
Count levelNails = nailboardLevelBits(nailboardNails(board), i); Count levelNails = nailboardLevelBits(nailboardNails(board), i);
Count resetNails = BTCountResRange(board->level[i], 0, levelNails); Count resetNails = BTCountResRange(board->level[i], 0, levelNails);
res = WriteF(stream, " Level $U ($U bits, $U set): ", res = WriteF(stream, depth + 2, "Level $U ($U bits, $U set): ",
i, levelNails, levelNails - resetNails, NULL); i, levelNails, levelNails - resetNails, NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;
for (j = 0; j < levelNails; ++j) { for (j = 0; j < levelNails; ++j) {
char c = BTGet(board->level[i], j) ? '*' : '.'; char c = BTGet(board->level[i], j) ? '*' : '.';
res = WriteF(stream, "$C", c, NULL); res = WriteF(stream, 0, "$C", c, NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;
} }
res = WriteF(stream, "\n", NULL); res = WriteF(stream, 0, "\n", NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;
} }
res = WriteF(stream, "}\n", NULL); res = WriteF(stream, depth, "} Nailboard $P\n", (WriteFP)board, NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;

View file

@ -45,7 +45,7 @@ extern Bool NailboardSet(Nailboard board, Addr addr);
extern void NailboardSetRange(Nailboard board, Addr base, Addr limit); extern void NailboardSetRange(Nailboard board, Addr base, Addr limit);
extern Bool NailboardIsSetRange(Nailboard board, Addr base, Addr limit); extern Bool NailboardIsSetRange(Nailboard board, Addr base, Addr limit);
extern Bool NailboardIsResRange(Nailboard board, Addr base, Addr limit); extern Bool NailboardIsResRange(Nailboard board, Addr base, Addr limit);
extern Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream); extern Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream, Count depth);
#endif /* nailboard.h */ #endif /* nailboard.h */

View file

@ -49,6 +49,8 @@ static void test(mps_arena_t arena)
"NailboardIsResRange"); "NailboardIsResRange");
} }
} }
die(NailboardDescribe(board, mps_lib_get_stdout(), 0), "NailboardDescribe");
} }
int main(int argc, char **argv) int main(int argc, char **argv)

View file

@ -72,6 +72,8 @@ Bool PoolClassCheck(PoolClass class)
CHECKL(FUNCHECK(class->bufferClass)); CHECKL(FUNCHECK(class->bufferClass));
CHECKL(FUNCHECK(class->describe)); CHECKL(FUNCHECK(class->describe));
CHECKL(FUNCHECK(class->debugMixin)); CHECKL(FUNCHECK(class->debugMixin));
CHECKL(FUNCHECK(class->totalSize));
CHECKL(FUNCHECK(class->freeSize));
CHECKS(PoolClass, class); CHECKS(PoolClass, class);
return TRUE; return TRUE;
} }
@ -114,6 +116,7 @@ ARG_DEFINE_KEY(min_size, Size);
ARG_DEFINE_KEY(mean_size, Size); ARG_DEFINE_KEY(mean_size, Size);
ARG_DEFINE_KEY(max_size, Size); ARG_DEFINE_KEY(max_size, Size);
ARG_DEFINE_KEY(align, Align); ARG_DEFINE_KEY(align, Align);
ARG_DEFINE_KEY(spare, double);
ARG_DEFINE_KEY(interior, Bool); ARG_DEFINE_KEY(interior, Bool);
@ -517,9 +520,29 @@ 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 */ /* PoolDescribe -- describe a pool */
Res PoolDescribe(Pool pool, mps_lib_FILE *stream) Res PoolDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Ring node, nextNode; Ring node, nextNode;
@ -527,7 +550,7 @@ Res PoolDescribe(Pool pool, mps_lib_FILE *stream)
if (!TESTT(Pool, pool)) return ResFAIL; if (!TESTT(Pool, pool)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Pool $P ($U) {\n", (WriteFP)pool, (WriteFU)pool->serial, "Pool $P ($U) {\n", (WriteFP)pool, (WriteFU)pool->serial,
" class $P (\"$S\")\n", " class $P (\"$S\")\n",
(WriteFP)pool->class, pool->class->name, (WriteFP)pool->class, pool->class->name,
@ -537,10 +560,10 @@ Res PoolDescribe(Pool pool, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (NULL != pool->format) { if (NULL != pool->format) {
res = FormatDescribe(pool->format, stream); res = FormatDescribe(pool->format, stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, res = WriteF(stream, depth + 2,
"fillMutatorSize $UKb\n", "fillMutatorSize $UKb\n",
(WriteFU)(pool->fillMutatorSize / 1024), (WriteFU)(pool->fillMutatorSize / 1024),
"emptyMutatorSize $UKb\n", "emptyMutatorSize $UKb\n",
@ -552,16 +575,16 @@ Res PoolDescribe(Pool pool, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = (*pool->class->describe)(pool, stream); res = (*pool->class->describe)(pool, stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
RING_FOR(node, &pool->bufferRing, nextNode) { RING_FOR(node, &pool->bufferRing, nextNode) {
Buffer buffer = RING_ELT(Buffer, poolRing, node); Buffer buffer = RING_ELT(Buffer, poolRing, node);
res = BufferDescribe(buffer, stream); res = BufferDescribe(buffer, stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, res = WriteF(stream, depth,
"} Pool $P ($U)\n", (WriteFP)pool, (WriteFU)pool->serial, "} Pool $P ($U)\n", (WriteFP)pool, (WriteFU)pool->serial,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
@ -622,29 +645,32 @@ Bool PoolOfAddr(Pool *poolReturn, Arena arena, Addr addr)
*/ */
Bool PoolOfRange(Pool *poolReturn, Arena arena, Addr base, Addr limit) Bool PoolOfRange(Pool *poolReturn, Arena arena, Addr base, Addr limit)
{ {
Pool pool; Bool havePool = FALSE;
Pool pool = NULL;
Tract tract; Tract tract;
Addr addr, alignedBase, alignedLimit;
AVER(poolReturn != NULL); AVER(poolReturn != NULL);
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(base < limit); AVER(base < limit);
if (!TractOfAddr(&tract, arena, base)) alignedBase = AddrArenaGrainDown(base, arena);
return FALSE; alignedLimit = AddrArenaGrainUp(limit, arena);
pool = TractPool(tract); TRACT_FOR(tract, addr, arena, alignedBase, alignedLimit) {
if (!pool) Pool p = TractPool(tract);
return FALSE; if (havePool && pool != p)
while (TractLimit(tract) < limit) {
if (!TractNext(&tract, arena, TractBase(tract)))
return FALSE;
if (TractPool(tract) != pool)
return FALSE; return FALSE;
pool = p;
havePool = TRUE;
} }
if (havePool) {
*poolReturn = pool; *poolReturn = pool;
return TRUE; return TRUE;
} else {
return FALSE;
}
} }

View file

@ -145,6 +145,8 @@ DEFINE_CLASS(AbstractPoolClass, class)
class->bufferClass = PoolNoBufferClass; class->bufferClass = PoolNoBufferClass;
class->describe = PoolTrivDescribe; class->describe = PoolTrivDescribe;
class->debugMixin = PoolNoDebugMixin; class->debugMixin = PoolNoDebugMixin;
class->totalSize = PoolNoSize;
class->freeSize = PoolNoSize;
class->labelled = FALSE; class->labelled = FALSE;
class->sig = PoolClassSig; class->sig = PoolClassSig;
} }
@ -290,11 +292,13 @@ void PoolTrivBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
} }
Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream) Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
AVERT(Pool, pool); AVERT(Pool, pool);
AVER(stream != NULL); AVER(stream != NULL);
return WriteF(stream, " No class-specific description available.\n", NULL); return WriteF(stream, depth,
"No class-specific description available.\n",
NULL);
} }
@ -675,6 +679,14 @@ BufferClass PoolNoBufferClass(void)
} }
Size PoolNoSize(Pool pool)
{
AVERT(Pool, pool);
NOTREACHED;
return UNUSED_SIZE;
}
/* C. COPYRIGHT AND LICENSE /* C. COPYRIGHT AND LICENSE
* *
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>. * Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.

View file

@ -48,7 +48,7 @@ typedef struct amcGenStruct {
Sig sig; /* <code/misc.h#sig> */ Sig sig; /* <code/misc.h#sig> */
} amcGenStruct; } amcGenStruct;
#define amcGenAMC(amcgen) Pool2AMC((amcgen)->pgen.pool) #define amcGenAMC(amcgen) PoolAMC((amcgen)->pgen.pool)
#define amcGenPool(amcgen) ((amcgen)->pgen.pool) #define amcGenPool(amcgen) ((amcgen)->pgen.pool)
#define amcGenNr(amcgen) ((amcgen)->pgen.nr) #define amcGenNr(amcgen) ((amcgen)->pgen.nr)
@ -235,7 +235,7 @@ static void AMCSegSketch(Seg seg, char *pbSketch, size_t cbSketch)
* *
* See <design/poolamc/#seg-describe>. * See <design/poolamc/#seg-describe>.
*/ */
static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream) static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Pool pool; Pool pool;
@ -256,7 +256,7 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream)
/* Describe the superclass fields first via next-method call */ /* Describe the superclass fields first via next-method call */
super = SEG_SUPERCLASS(amcSegClass); super = SEG_SUPERCLASS(amcSegClass);
res = super->describe(seg, stream); res = super->describe(seg, stream, depth);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -268,7 +268,7 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream)
p = AddrAdd(base, pool->format->headerSize); p = AddrAdd(base, pool->format->headerSize);
limit = SegLimit(seg); limit = SegLimit(seg);
res = WriteF(stream, res = WriteF(stream, depth,
"AMC seg $P [$A,$A){\n", "AMC seg $P [$A,$A){\n",
(WriteFP)seg, (WriteFA)base, (WriteFA)limit, (WriteFP)seg, (WriteFA)base, (WriteFA)limit,
NULL); NULL);
@ -276,16 +276,17 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream)
return res; return res;
if(amcSegHasNailboard(seg)) { if(amcSegHasNailboard(seg)) {
res = WriteF(stream, " Boarded\n", NULL); res = WriteF(stream, depth + 2, "Boarded\n", NULL);
} else if(SegNailed(seg) == TraceSetEMPTY) { } else if(SegNailed(seg) == TraceSetEMPTY) {
res = WriteF(stream, " Mobile\n", NULL); res = WriteF(stream, depth + 2, "Mobile\n", NULL);
} else { } else {
res = WriteF(stream, " Stuck\n", NULL); res = WriteF(stream, depth + 2, "Stuck\n", NULL);
} }
if(res != ResOK) if(res != ResOK)
return res; return res;
res = WriteF(stream, " Map: *===:object @+++:nails bbbb:buffer\n", NULL); res = WriteF(stream, depth + 2,
"Map: *===:object @+++:nails bbbb:buffer\n", NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -298,7 +299,7 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream)
Addr j; Addr j;
char c; char c;
res = WriteF(stream, " $A ", i, NULL); res = WriteF(stream, depth + 2, "$A ", i, NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -318,22 +319,22 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream)
c = (nailed ? '+' : '='); c = (nailed ? '+' : '=');
} }
} }
res = WriteF(stream, "$C", c, NULL); res = WriteF(stream, 0, "$C", c, NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
} }
res = WriteF(stream, "\n", NULL); res = WriteF(stream, 0, "\n", NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
} }
AMCSegSketch(seg, abzSketch, NELEMS(abzSketch)); AMCSegSketch(seg, abzSketch, NELEMS(abzSketch));
res = WriteF(stream, " Sketch: $S\n", (WriteFS)abzSketch, NULL); res = WriteF(stream, depth + 2, "Sketch: $S\n", (WriteFS)abzSketch, NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
res = WriteF(stream, "} AMC Seg $P\n", (WriteFP)seg, NULL); res = WriteF(stream, depth, "} AMC Seg $P\n", (WriteFP)seg, NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -478,8 +479,8 @@ typedef struct AMCStruct { /* <design/poolamc/#struct> */
Sig sig; /* <design/pool/#outer-structure.sig> */ Sig sig; /* <design/pool/#outer-structure.sig> */
} AMCStruct; } AMCStruct;
#define Pool2AMC(pool) PARENT(AMCStruct, poolStruct, (pool)) #define PoolAMC(pool) PARENT(AMCStruct, poolStruct, (pool))
#define AMC2Pool(amc) (&(amc)->poolStruct) #define AMCPool(amc) (&(amc)->poolStruct)
/* amcGenCheck -- check consistency of a generation structure */ /* amcGenCheck -- check consistency of a generation structure */
@ -583,7 +584,7 @@ static Res AMCBufInit(Buffer buffer, Pool pool, ArgList args)
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
if (ArgPick(&arg, args, amcKeyAPHashArrays)) if (ArgPick(&arg, args, amcKeyAPHashArrays))
@ -656,7 +657,7 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen)
Res res; Res res;
void *p; void *p;
pool = AMC2Pool(amc); pool = AMCPool(amc);
arena = pool->arena; arena = pool->arena;
res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE); res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE);
@ -712,21 +713,26 @@ static void amcGenDestroy(amcGen gen)
/* amcGenDescribe -- describe an AMC generation */ /* amcGenDescribe -- describe an AMC generation */
static Res amcGenDescribe(amcGen gen, mps_lib_FILE *stream) static Res amcGenDescribe(amcGen gen, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
if(!TESTT(amcGen, gen)) if(!TESTT(amcGen, gen))
return ResFAIL; return ResFAIL;
if (stream == NULL)
return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"amcGen $P {\n", (WriteFP)gen, "amcGen $P {\n", (WriteFP)gen,
" buffer $P\n", gen->forward, " buffer $P\n", gen->forward, NULL);
" segs $U, totalSize $U, newSize $U\n", if (res != ResOK)
(WriteFU)gen->pgen.segs, return res;
(WriteFU)gen->pgen.totalSize,
(WriteFU)gen->pgen.newSize, res = PoolGenDescribe(&gen->pgen, stream, depth + 2);
" } amcGen\n", NULL); if (res != ResOK)
return res;
res = WriteF(stream, depth, "} amcGen $P\n", (WriteFP)gen, NULL);
return res; return res;
} }
@ -757,7 +763,7 @@ static Res amcSegCreateNailboard(Seg seg, Pool pool)
static Bool amcPinnedInterior(AMC amc, Nailboard board, Addr base, Addr limit) static Bool amcPinnedInterior(AMC amc, Nailboard board, Addr base, Addr limit)
{ {
Size headerSize = AMC2Pool(amc)->format->headerSize; Size headerSize = AMCPool(amc)->format->headerSize;
return !NailboardIsResRange(board, AddrSub(base, headerSize), return !NailboardIsResRange(board, AddrSub(base, headerSize),
AddrSub(limit, headerSize)); AddrSub(limit, headerSize));
} }
@ -817,7 +823,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
AVER(pool != NULL); AVER(pool != NULL);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
arena = PoolArena(pool); arena = PoolArena(pool);
ArgRequire(&arg, args, MPS_KEY_FORMAT); ArgRequire(&arg, args, MPS_KEY_FORMAT);
@ -933,7 +939,7 @@ static void AMCFinish(Pool pool)
Ring node, nextNode; Ring node, nextNode;
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
EVENT1(AMCFinish, amc); EVENT1(AMCFinish, amc);
@ -995,7 +1001,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
amcBuf amcbuf; amcBuf amcbuf;
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
AVER(baseReturn != NULL); AVER(baseReturn != NULL);
AVER(limitReturn != NULL); AVER(limitReturn != NULL);
@ -1084,7 +1090,7 @@ static void AMCBufferEmpty(Pool pool, Buffer buffer,
Seg seg; Seg seg;
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(BufferIsReady(buffer)); AVER(BufferIsReady(buffer));
@ -1123,7 +1129,7 @@ static void AMCRampBegin(Pool pool, Buffer buf, Bool collectAll)
AMC amc; AMC amc;
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
AVERT(Buffer, buf); AVERT(Buffer, buf);
AVERT(Bool, collectAll); AVERT(Bool, collectAll);
@ -1145,7 +1151,7 @@ static void AMCRampEnd(Pool pool, Buffer buf)
AMC amc; AMC amc;
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
AVERT(Buffer, buf); AVERT(Buffer, buf);
@ -1277,7 +1283,7 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
condemned += SegSize(seg); condemned += SegSize(seg);
trace->condemned += condemned; trace->condemned += condemned;
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
STATISTIC_STAT( { STATISTIC_STAT( {
@ -1334,7 +1340,7 @@ static Res amcScanNailedRange(Bool *totalReturn, Bool *moreReturn,
Format format; Format format;
Size headerSize; Size headerSize;
Addr p, clientLimit; Addr p, clientLimit;
Pool pool = AMC2Pool(amc); Pool pool = AMCPool(amc);
format = pool->format; format = pool->format;
headerSize = format->headerSize; headerSize = format->headerSize;
p = AddrAdd(base, headerSize); p = AddrAdd(base, headerSize);
@ -1477,7 +1483,7 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVERT(ScanState, ss); AVERT(ScanState, ss);
AVERT(Seg, seg); AVERT(Seg, seg);
AVERT(Pool, pool); AVERT(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
@ -1589,7 +1595,7 @@ static Res AMCFixEmergency(Pool pool, ScanState ss, Seg seg,
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Arena, arena); AVERT(Arena, arena);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
ss->wasMarked = TRUE; ss->wasMarked = TRUE;
@ -1667,7 +1673,7 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
return ResOK; return ResOK;
} }
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT_CRITICAL(AMC, amc); AVERT_CRITICAL(AMC, amc);
format = pool->format; format = pool->format;
ref = *refIO; ref = *refIO;
@ -1816,7 +1822,7 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
return ResOK; return ResOK;
} }
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT_CRITICAL(AMC, amc); AVERT_CRITICAL(AMC, amc);
format = pool->format; format = pool->format;
headerSize = format->headerSize; headerSize = format->headerSize;
@ -1930,7 +1936,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
/* All arguments AVERed by AMCReclaim */ /* All arguments AVERed by AMCReclaim */
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
format = pool->format; format = pool->format;
@ -2048,7 +2054,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg)
amcGen gen; amcGen gen;
AVERT_CRITICAL(Pool, pool); AVERT_CRITICAL(Pool, pool);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT_CRITICAL(AMC, amc); AVERT_CRITICAL(AMC, amc);
AVERT_CRITICAL(Trace, trace); AVERT_CRITICAL(Trace, trace);
AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(Seg, seg);
@ -2094,7 +2100,7 @@ static void AMCTraceEnd(Pool pool, Trace trace)
AVERT(Pool, pool); AVERT(Pool, pool);
AVERT(Trace, trace); AVERT(Trace, trace);
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
ti = trace->ti; ti = trace->ti;
AVERT(TraceId, ti); AVERT(TraceId, ti);
@ -2138,7 +2144,7 @@ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
if(SegWhite(seg) == TraceSetEMPTY && SegGrey(seg) == TraceSetEMPTY if(SegWhite(seg) == TraceSetEMPTY && SegGrey(seg) == TraceSetEMPTY
&& SegNailed(seg) == TraceSetEMPTY) && SegNailed(seg) == TraceSetEMPTY)
{ {
amc = Pool2AMC(pool); amc = PoolAMC(pool);
AVERT(AMC, amc); AVERT(AMC, amc);
format = pool->format; format = pool->format;
@ -2266,11 +2272,55 @@ 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 /* AMCDescribe -- describe the contents of the AMC pool
* *
* See <design/poolamc/#describe>. * See <design/poolamc/#describe>.
*/ */
static Res AMCDescribe(Pool pool, mps_lib_FILE *stream) static Res AMCDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
AMC amc; AMC amc;
@ -2279,59 +2329,55 @@ static Res AMCDescribe(Pool pool, mps_lib_FILE *stream)
if(!TESTT(Pool, pool)) if(!TESTT(Pool, pool))
return ResFAIL; return ResFAIL;
amc = Pool2AMC(pool); amc = PoolAMC(pool);
if(!TESTT(AMC, amc)) if(!TESTT(AMC, amc))
return ResFAIL; return ResFAIL;
if(stream == NULL) if(stream == NULL)
return ResFAIL; return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
(amc->rankSet == RankSetEMPTY) ? "AMCZ" : "AMC", (amc->rankSet == RankSetEMPTY) ? "AMCZ" : "AMC",
" $P {\n", (WriteFP)amc, " pool $P ($U)\n", " $P {\n", (WriteFP)amc, " pool $P ($U)\n",
(WriteFP)AMC2Pool(amc), (WriteFU)AMC2Pool(amc)->serial, (WriteFP)AMCPool(amc), (WriteFU)AMCPool(amc)->serial,
NULL); NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
switch(amc->rampMode) { switch(amc->rampMode) {
#define RAMP_DESCRIBE(e, s) \ #define RAMP_DESCRIBE(e, s) \
case e: \ case e: \
rampmode = s; \ rampmode = s; \
break; break;
RAMP_RELATION(RAMP_DESCRIBE) RAMP_RELATION(RAMP_DESCRIBE)
#undef RAMP_DESCRIBE #undef RAMP_DESCRIBE
default: default:
rampmode = "unknown ramp mode"; rampmode = "unknown ramp mode";
break; break;
} }
res = WriteF(stream, res = WriteF(stream, depth + 2,
" ", rampmode, " ($U)\n", (WriteFU)amc->rampCount, rampmode, " ($U)\n", (WriteFU)amc->rampCount,
NULL); NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
RING_FOR(node, &amc->genRing, nextNode) { RING_FOR(node, &amc->genRing, nextNode) {
amcGen gen = RING_ELT(amcGen, amcRing, node); amcGen gen = RING_ELT(amcGen, amcRing, node);
res = amcGenDescribe(gen, stream); res = amcGenDescribe(gen, stream, depth + 2);
if(res != ResOK) if(res != ResOK)
return res; return res;
} }
if(0) { if(0) {
/* SegDescribes */ /* SegDescribes */
RING_FOR(node, &AMC2Pool(amc)->segRing, nextNode) { RING_FOR(node, &AMCPool(amc)->segRing, nextNode) {
Seg seg = RING_ELT(Seg, poolRing, node); Seg seg = RING_ELT(Seg, poolRing, node);
res = AMCSegDescribe(seg, stream); res = AMCSegDescribe(seg, stream, depth + 2);
if(res != ResOK) if(res != ResOK)
return res; return res;
} }
} }
res = WriteF(stream, "} AMC $P\n", (WriteFP)amc, NULL); res = WriteF(stream, depth, "} AMC $P\n", (WriteFP)amc, NULL);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -2365,6 +2411,8 @@ DEFINE_POOL_CLASS(AMCZPoolClass, this)
this->addrObject = AMCAddrObject; this->addrObject = AMCAddrObject;
this->walk = AMCWalk; this->walk = AMCWalk;
this->bufferClass = amcBufClassGet; this->bufferClass = amcBufClassGet;
this->totalSize = AMCTotalSize;
this->freeSize = AMCFreeSize;
this->describe = AMCDescribe; this->describe = AMCDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -2458,8 +2506,8 @@ ATTRIBUTE_UNUSED
static Bool AMCCheck(AMC amc) static Bool AMCCheck(AMC amc)
{ {
CHECKS(AMC, amc); CHECKS(AMC, amc);
CHECKD(Pool, &amc->poolStruct); CHECKD(Pool, AMCPool(amc));
CHECKL(IsSubclassPoly(amc->poolStruct.class, AMCZPoolClassGet())); CHECKL(IsSubclassPoly(AMCPool(amc)->class, AMCZPoolClassGet()));
CHECKL(RankSetCheck(amc->rankSet)); CHECKL(RankSetCheck(amc->rankSet));
CHECKD_NOSIG(Ring, &amc->genRing); CHECKD_NOSIG(Ring, &amc->genRing);
CHECKL(BoolCheck(amc->gensBooted)); CHECKL(BoolCheck(amc->gensBooted));

View file

@ -50,7 +50,7 @@ Bool AMSSegCheck(AMSSeg amsseg)
CHECKS(AMSSeg, amsseg); CHECKS(AMSSeg, amsseg);
CHECKD(GCSeg, &amsseg->gcSegStruct); CHECKD(GCSeg, &amsseg->gcSegStruct);
CHECKU(AMS, amsseg->ams); CHECKU(AMS, amsseg->ams);
CHECKL(AMS2Pool(amsseg->ams) == SegPool(seg)); CHECKL(AMSPool(amsseg->ams) == SegPool(seg));
CHECKD_NOSIG(Ring, &amsseg->segRing); CHECKD_NOSIG(Ring, &amsseg->segRing);
CHECKL(amsseg->grains == AMSGrains(amsseg->ams, SegSize(seg))); CHECKL(amsseg->grains == AMSGrains(amsseg->ams, SegSize(seg)));
@ -226,7 +226,7 @@ static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Seg, seg); AVERT(Seg, seg);
amsseg = Seg2AMSSeg(seg); amsseg = Seg2AMSSeg(seg);
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
arena = PoolArena(pool); arena = PoolArena(pool);
/* no useful checks for base and size */ /* no useful checks for base and size */
@ -287,7 +287,7 @@ static void AMSSegFinish(Seg seg)
AVERT(AMSSeg, amsseg); AVERT(AMSSeg, amsseg);
ams = amsseg->ams; ams = amsseg->ams;
AVERT(AMS, ams); AVERT(AMS, ams);
arena = PoolArena(AMS2Pool(ams)); arena = PoolArena(AMSPool(ams));
AVER(SegBuffer(seg) == NULL); AVER(SegBuffer(seg) == NULL);
/* keep the destructions in step with AMSSegInit failure cases */ /* keep the destructions in step with AMSSegInit failure cases */
@ -346,7 +346,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
AVERT(AMSSeg, amssegHi); AVERT(AMSSeg, amssegHi);
/* other parameters are checked by next-method */ /* other parameters are checked by next-method */
arena = PoolArena(SegPool(seg)); arena = PoolArena(SegPool(seg));
ams = Pool2AMS(SegPool(seg)); ams = PoolAMS(SegPool(seg));
loGrains = amsseg->grains; loGrains = amsseg->grains;
hiGrains = amssegHi->grains; hiGrains = amssegHi->grains;
@ -432,7 +432,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi,
AVERT(AMSSeg, amsseg); AVERT(AMSSeg, amsseg);
/* other parameters are checked by next-method */ /* other parameters are checked by next-method */
arena = PoolArena(SegPool(seg)); arena = PoolArena(SegPool(seg));
ams = Pool2AMS(SegPool(seg)); ams = PoolAMS(SegPool(seg));
loGrains = AMSGrains(ams, AddrOffset(base, mid)); loGrains = AMSGrains(ams, AddrOffset(base, mid));
hiGrains = AMSGrains(ams, AddrOffset(mid, limit)); hiGrains = AMSGrains(ams, AddrOffset(mid, limit));
@ -526,12 +526,12 @@ failCreateTablesLo:
BEGIN \ BEGIN \
if ((buffer) != NULL \ if ((buffer) != NULL \
&& (i) == AMS_ADDR_INDEX(seg, accessor(buffer))) { \ && (i) == AMS_ADDR_INDEX(seg, accessor(buffer))) { \
Res _res = WriteF(stream, char, NULL); \ Res _res = WriteF(stream, 0, char, NULL); \
if (_res != ResOK) return _res; \ if (_res != ResOK) return _res; \
} \ } \
END END
static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream) static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
AMSSeg amsseg; AMSSeg amsseg;
@ -546,12 +546,12 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream)
/* Describe the superclass fields first via next-method call */ /* Describe the superclass fields first via next-method call */
super = SEG_SUPERCLASS(AMSSegClass); super = SEG_SUPERCLASS(AMSSegClass);
res = super->describe(seg, stream); res = super->describe(seg, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
buffer = SegBuffer(seg); buffer = SegBuffer(seg);
res = WriteF(stream, res = WriteF(stream, depth,
" AMS $P\n", (WriteFP)amsseg->ams, " AMS $P\n", (WriteFP)amsseg->ams,
" grains $W\n", (WriteFW)amsseg->grains, " grains $W\n", (WriteFW)amsseg->grains,
" freeGrains $W\n", (WriteFW)amsseg->freeGrains, " freeGrains $W\n", (WriteFW)amsseg->freeGrains,
@ -560,19 +560,19 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (amsseg->allocTableInUse) if (amsseg->allocTableInUse)
res = WriteF(stream, res = WriteF(stream, depth,
"alloctable $P\n", (WriteFP)amsseg->allocTable, "alloctable $P\n", (WriteFP)amsseg->allocTable,
NULL); NULL);
else else
res = WriteF(stream, res = WriteF(stream, depth,
"firstFree $W\n", (WriteFW)amsseg->firstFree, "firstFree $W\n", (WriteFW)amsseg->firstFree,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth,
"tables: nongrey $P, nonwhite $P\n", "tables: nongrey $P, nonwhite $P\n",
(WriteFP)amsseg->nongreyTable, (WriteFP)amsseg->nongreyTable,
(WriteFP)amsseg->nonwhiteTable, (WriteFP)amsseg->nonwhiteTable,
" map: \n", "map:",
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
@ -580,7 +580,9 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream)
char c = 0; char c = 0;
if (i % 64 == 0) { if (i % 64 == 0) {
res = WriteF(stream, "\n ", NULL); res = WriteF(stream, 0, "\n", NULL);
if (res != ResOK) return res;
res = WriteF(stream, depth, " ", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
@ -602,7 +604,7 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream)
c = '.'; c = '.';
} else } else
c = ' '; c = ' ';
res = WriteF(stream, "$C", c, NULL); res = WriteF(stream, 0, "$C", c, NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;
@ -610,8 +612,7 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream)
WRITE_BUFFER_LIMIT(stream, seg, i+1, buffer, BufferLimit, "]"); WRITE_BUFFER_LIMIT(stream, seg, i+1, buffer, BufferLimit, "]");
} }
res = WriteF(stream, "\n", NULL); return ResOK;
return res;
} }
@ -631,8 +632,6 @@ DEFINE_CLASS(AMSSegClass, class)
} }
/* AMSPoolRing -- the ring of segments in the pool */ /* AMSPoolRing -- the ring of segments in the pool */
static Ring AMSPoolRing(AMS ams, RankSet rankSet, Size size) static Ring AMSPoolRing(AMS ams, RankSet rankSet, Size size)
@ -687,7 +686,7 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size,
AVERT(RankSet, rankSet); AVERT(RankSet, rankSet);
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS,ams); AVERT(AMS,ams);
arena = PoolArena(pool); arena = PoolArena(pool);
@ -732,7 +731,7 @@ static void AMSSegsDestroy(AMS ams)
{ {
Ring ring, node, next; /* for iterating over the segments */ Ring ring, node, next; /* for iterating over the segments */
ring = PoolSegRing(AMS2Pool(ams)); ring = PoolSegRing(AMSPool(ams));
RING_FOR(node, ring, next) { RING_FOR(node, ring, next) {
Seg seg = SegOfPoolRing(node); Seg seg = SegOfPoolRing(node);
AMSSeg amsseg = Seg2AMSSeg(seg); AMSSeg amsseg = Seg2AMSSeg(seg);
@ -805,7 +804,7 @@ static Res AMSInit(Pool pool, ArgList args)
/* .ambiguous.noshare: If the pool is required to support ambiguous */ /* .ambiguous.noshare: If the pool is required to support ambiguous */
/* references, the alloc and white tables cannot be shared. */ /* references, the alloc and white tables cannot be shared. */
res = AMSInitInternal(Pool2AMS(pool), format, chain, gen, !supportAmbiguous); res = AMSInitInternal(PoolAMS(pool), format, chain, gen, !supportAmbiguous);
if (res == ResOK) { if (res == ResOK) {
EVENT3(PoolInitAMS, pool, PoolArena(pool), format); EVENT3(PoolInitAMS, pool, PoolArena(pool), format);
} }
@ -826,7 +825,7 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
AVERT(Chain, chain); AVERT(Chain, chain);
AVER(gen <= ChainGens(chain)); AVER(gen <= ChainGens(chain));
pool = AMS2Pool(ams); pool = AMSPool(ams);
AVERT(Pool, pool); AVERT(Pool, pool);
pool->format = format; pool->format = format;
pool->alignment = pool->format->alignment; pool->alignment = pool->format->alignment;
@ -862,7 +861,7 @@ void AMSFinish(Pool pool)
AMS ams; AMS ams;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
(ams->segsDestroy)(ams); (ams->segsDestroy)(ams);
@ -896,7 +895,7 @@ static Bool amsSegAlloc(Index *baseReturn, Index *limitReturn,
AVERT(AMS, ams); AVERT(AMS, ams);
AVER(size > 0); AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(AMS2Pool(ams)))); AVER(SizeIsAligned(size, PoolAlignment(AMSPool(ams))));
grains = AMSGrains(ams, size); grains = AMSGrains(ams, size);
AVER(grains > 0); AVER(grains > 0);
@ -951,7 +950,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(baseReturn != NULL); AVER(baseReturn != NULL);
AVER(limitReturn != NULL); AVER(limitReturn != NULL);
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(size > 0); AVER(size > 0);
@ -1018,7 +1017,7 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
Size size; Size size;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
AVERT(Buffer,buffer); AVERT(Buffer,buffer);
AVER(BufferIsReady(buffer)); AVER(BufferIsReady(buffer));
@ -1109,7 +1108,7 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg)
Count uncondemned; Count uncondemned;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
AVERT(Trace, trace); AVERT(Trace, trace);
@ -1214,9 +1213,9 @@ static Res amsIterate(Seg seg, AMSObjectFunction f, void *closure)
AVERT(AMSSeg, amsseg); AVERT(AMSSeg, amsseg);
ams = amsseg->ams; ams = amsseg->ams;
AVERT(AMS, ams); AVERT(AMS, ams);
format = AMS2Pool(ams)->format; format = AMSPool(ams)->format;
AVERT(Format, format); AVERT(Format, format);
alignment = PoolAlignment(AMS2Pool(ams)); alignment = PoolAlignment(AMSPool(ams));
/* If we're using the alloc table as a white table, we can't use it to */ /* If we're using the alloc table as a white table, we can't use it to */
/* determine where there are objects. */ /* determine where there are objects. */
@ -1302,7 +1301,7 @@ static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos)
AVERT(ScanState, closure->ss); AVERT(ScanState, closure->ss);
AVERT(Bool, closure->scanAllObjects); AVERT(Bool, closure->scanAllObjects);
format = AMS2Pool(amsseg->ams)->format; format = AMSPool(amsseg->ams)->format;
AVERT(Format, format); AVERT(Format, format);
/* @@@@ This isn't quite right for multiple traces. */ /* @@@@ This isn't quite right for multiple traces. */
@ -1343,7 +1342,7 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVER(totalReturn != NULL); AVER(totalReturn != NULL);
AVERT(ScanState, ss); AVERT(ScanState, ss);
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Seg, seg); AVERT(Seg, seg);
@ -1371,7 +1370,7 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVER(amsseg->colourTablesInUse); AVER(amsseg->colourTablesInUse);
format = pool->format; format = pool->format;
AVERT(Format, format); AVERT(Format, format);
alignment = PoolAlignment(AMS2Pool(ams)); alignment = PoolAlignment(AMSPool(ams));
do { /* <design/poolams/#scan.iter> */ do { /* <design/poolams/#scan.iter> */
amsseg->marksChanged = FALSE; /* <design/poolams/#marked.scan> */ amsseg->marksChanged = FALSE; /* <design/poolams/#marked.scan> */
/* <design/poolams/#ambiguous.middle> */ /* <design/poolams/#ambiguous.middle> */
@ -1436,7 +1435,7 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
Format format; Format format;
AVERT_CRITICAL(Pool, pool); AVERT_CRITICAL(Pool, pool);
AVER_CRITICAL(TESTT(AMS, Pool2AMS(pool))); AVER_CRITICAL(TESTT(AMS, PoolAMS(pool)));
AVERT_CRITICAL(ScanState, ss); AVERT_CRITICAL(ScanState, ss);
AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(Seg, seg);
AVER_CRITICAL(refIO != NULL); AVER_CRITICAL(refIO != NULL);
@ -1474,7 +1473,7 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
switch (ss->rank) { switch (ss->rank) {
case RankAMBIG: case RankAMBIG:
if (Pool2AMS(pool)->shareAllocTable) if (PoolAMS(pool)->shareAllocTable)
/* In this state, the pool doesn't support ambiguous references (see */ /* In this state, the pool doesn't support ambiguous references (see */
/* .ambiguous.noshare), so this is not a reference. */ /* .ambiguous.noshare), so this is not a reference. */
break; break;
@ -1551,7 +1550,7 @@ static void AMSBlacken(Pool pool, TraceSet traceSet, Seg seg)
Res res; Res res;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
AVERT(TraceSet, traceSet); AVERT(TraceSet, traceSet);
AVERT(Seg, seg); AVERT(Seg, seg);
@ -1578,7 +1577,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
PoolDebugMixin debug; PoolDebugMixin debug;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
AVERT(Trace, trace); AVERT(Trace, trace);
AVERT(Seg, seg); AVERT(Seg, seg);
@ -1650,7 +1649,7 @@ static void AMSFreeWalk(Pool pool, FreeBlockStepMethod f, void *p)
Ring node, ring, nextNode; /* for iterating over the segments */ Ring node, ring, nextNode; /* for iterating over the segments */
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
ring = &ams->segRing; ring = &ams->segRing;
@ -1660,22 +1659,50 @@ 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 /* AMSDescribe -- the pool class description method
* *
* Iterates over the segments, describing all of them. * Iterates over the segments, describing all of them.
*/ */
static Res AMSDescribe(Pool pool, mps_lib_FILE *stream) static Res AMSDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
AMS ams; AMS ams;
Ring node, nextNode; Ring node, nextNode;
Res res; Res res;
if (!TESTT(Pool, pool)) return ResFAIL; if (!TESTT(Pool, pool)) return ResFAIL;
ams = Pool2AMS(pool); ams = PoolAMS(pool);
if (!TESTT(AMS, ams)) return ResFAIL; if (!TESTT(AMS, ams)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"AMS $P {\n", (WriteFP)ams, "AMS $P {\n", (WriteFP)ams,
" pool $P ($U)\n", " pool $P ($U)\n",
(WriteFP)pool, (WriteFU)pool->serial, (WriteFP)pool, (WriteFU)pool->serial,
@ -1683,21 +1710,19 @@ static Res AMSDescribe(Pool pool, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth + 2,
" segments\n" "segments: * black + grey - white . alloc ! bad\n"
" * = black, + = grey, - = white, . = alloc, ! = bad\n" "buffers: [ base < scan limit | init > alloc ] limit\n",
" buffers: [ = base, < = scan limit, | = init,\n"
" > = alloc, ] = limit\n",
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
RING_FOR(node, &ams->segRing, nextNode) { RING_FOR(node, &ams->segRing, nextNode) {
AMSSeg amsseg = RING_ELT(AMSSeg, segRing, node); AMSSeg amsseg = RING_ELT(AMSSeg, segRing, node);
res = SegDescribe(AMSSeg2Seg(amsseg), stream); res = SegDescribe(AMSSeg2Seg(amsseg), stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, "} AMS $P\n",(WriteFP)ams, NULL); res = WriteF(stream, depth, "} AMS $P\n",(WriteFP)ams, NULL);
if (res != ResOK) if (res != ResOK)
return res; return res;
@ -1731,6 +1756,8 @@ DEFINE_CLASS(AMSPoolClass, this)
this->reclaim = AMSReclaim; this->reclaim = AMSReclaim;
this->walk = PoolNoWalk; /* TODO: job003738 */ this->walk = PoolNoWalk; /* TODO: job003738 */
this->freewalk = AMSFreeWalk; this->freewalk = AMSFreeWalk;
this->totalSize = AMSTotalSize;
this->freeSize = AMSFreeSize;
this->describe = AMSDescribe; this->describe = AMSDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -1743,7 +1770,7 @@ static PoolDebugMixin AMSDebugMixin(Pool pool)
AMS ams; AMS ams;
AVERT(Pool, pool); AVERT(Pool, pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
AVERT(AMS, ams); AVERT(AMS, ams);
/* Can't check AMSDebug, because this is called during init */ /* Can't check AMSDebug, because this is called during init */
return &(AMS2AMSDebug(ams)->debug); return &(AMS2AMSDebug(ams)->debug);
@ -1769,10 +1796,10 @@ DEFINE_POOL_CLASS(AMSDebugPoolClass, this)
Bool AMSCheck(AMS ams) Bool AMSCheck(AMS ams)
{ {
CHECKS(AMS, ams); CHECKS(AMS, ams);
CHECKD(Pool, AMS2Pool(ams)); CHECKD(Pool, AMSPool(ams));
CHECKL(IsSubclassPoly(AMS2Pool(ams)->class, AMSPoolClassGet())); CHECKL(IsSubclassPoly(AMSPool(ams)->class, AMSPoolClassGet()));
CHECKL(PoolAlignment(AMS2Pool(ams)) == AMSGrainsSize(ams, (Size)1)); CHECKL(PoolAlignment(AMSPool(ams)) == AMSGrainsSize(ams, (Size)1));
CHECKL(PoolAlignment(AMS2Pool(ams)) == AMS2Pool(ams)->format->alignment); CHECKL(PoolAlignment(AMSPool(ams)) == AMSPool(ams)->format->alignment);
CHECKD(PoolGen, &ams->pgen); CHECKD(PoolGen, &ams->pgen);
CHECKL(FUNCHECK(ams->segSize)); CHECKL(FUNCHECK(ams->segSize));
CHECKD_NOSIG(Ring, &ams->segRing); CHECKD_NOSIG(Ring, &ams->segRing);

View file

@ -79,8 +79,8 @@ typedef struct AMSSegStruct {
#define Seg2AMSSeg(seg) ((AMSSeg)(seg)) #define Seg2AMSSeg(seg) ((AMSSeg)(seg))
#define AMSSeg2Seg(amsseg) ((Seg)(amsseg)) #define AMSSeg2Seg(amsseg) ((Seg)(amsseg))
#define Pool2AMS(pool) PARENT(AMSStruct, poolStruct, pool) #define PoolAMS(pool) PARENT(AMSStruct, poolStruct, pool)
#define AMS2Pool(ams) (&(ams)->poolStruct) #define AMSPool(ams) (&(ams)->poolStruct)
/* macros for abstracting index/address computations */ /* macros for abstracting index/address computations */

View file

@ -91,7 +91,8 @@ typedef struct AWLStruct {
Sig sig; Sig sig;
} AWLStruct, *AWL; } AWLStruct, *AWL;
#define Pool2AWL(pool) PARENT(AWLStruct, poolStruct, pool) #define PoolAWL(pool) PARENT(AWLStruct, poolStruct, pool)
#define AWLPool(awl) (&(awl)->poolStruct)
#define AWLGrainsSize(awl, grains) ((grains) << (awl)->alignShift) #define AWLGrainsSize(awl, grains) ((grains) << (awl)->alignShift)
@ -198,7 +199,7 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size,
/* AWL only accepts two ranks */ /* AWL only accepts two ranks */
AVER(RankSetSingle(RankEXACT) == rankSet AVER(RankSetSingle(RankEXACT) == rankSet
|| RankSetSingle(RankWEAK) == rankSet); || RankSetSingle(RankWEAK) == rankSet);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
/* Initialize the superclass fields first via next-method call */ /* Initialize the superclass fields first via next-method call */
@ -262,7 +263,7 @@ static void AWLSegFinish(Seg seg)
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
pool = SegPool(seg); pool = SegPool(seg);
AVERT(Pool, pool); AVERT(Pool, pool);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Arena, arena); AVERT(Arena, arena);
@ -465,7 +466,7 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn,
AVER(size > 0); AVER(size > 0);
AVERT(Bool, reservoirPermit); AVERT(Bool, reservoirPermit);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
arena = PoolArena(pool); arena = PoolArena(pool);
@ -549,7 +550,7 @@ static Res AWLInit(Pool pool, ArgList args)
/* Weak check, as half-way through initialization. */ /* Weak check, as half-way through initialization. */
AVER(pool != NULL); AVER(pool != NULL);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
ArgRequire(&arg, args, MPS_KEY_FORMAT); ArgRequire(&arg, args, MPS_KEY_FORMAT);
format = arg.val.format; format = arg.val.format;
@ -602,7 +603,7 @@ static void AWLFinish(Pool pool)
AVERT(Pool, pool); AVERT(Pool, pool);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
ring = &pool->segRing; ring = &pool->segRing;
@ -640,7 +641,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(size > 0); AVER(size > 0);
AVERT(Bool, reservoirPermit); AVERT(Bool, reservoirPermit);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
RING_FOR(node, &pool->segRing, nextNode) { RING_FOR(node, &pool->segRing, nextNode) {
@ -708,7 +709,7 @@ static void AWLBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
AVERT(Seg, seg); AVERT(Seg, seg);
AVER(init <= limit); AVER(init <= limit);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -753,7 +754,7 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg)
/* All parameters checked by generic PoolWhiten. */ /* All parameters checked by generic PoolWhiten. */
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -819,7 +820,7 @@ static void AWLGrey(Pool pool, Trace trace, Seg seg)
AWL awl; AWL awl;
AWLSeg awlseg; AWLSeg awlseg;
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -853,7 +854,7 @@ static void AWLBlacken(Pool pool, TraceSet traceSet, Seg seg)
AVERT(TraceSet, traceSet); AVERT(TraceSet, traceSet);
AVERT(Seg, seg); AVERT(Seg, seg);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -920,7 +921,7 @@ static Res awlScanSinglePass(Bool *anyScannedReturn,
AVERT(Seg, seg); AVERT(Seg, seg);
AVERT(Bool, scanAllObjects); AVERT(Bool, scanAllObjects);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Arena, arena); AVERT(Arena, arena);
@ -996,7 +997,7 @@ static Res AWLScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
/* If the scanner isn't going to scan all the objects then the */ /* If the scanner isn't going to scan all the objects then the */
@ -1046,7 +1047,7 @@ static Res AWLFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
AVER(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY); AVER(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY);
AVER(refIO != NULL); AVER(refIO != NULL);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -1110,7 +1111,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
AVERT(Trace, trace); AVERT(Trace, trace);
AVERT(Seg, seg); AVERT(Seg, seg);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -1188,7 +1189,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr,
Res res; Res res;
AVERT(Pool, pool); AVERT(Pool, pool);
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
AVERT(Seg, seg); AVERT(Seg, seg);
AVER(SegBase(seg) <= addr); AVER(SegBase(seg) <= addr);
@ -1235,7 +1236,7 @@ static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
AVER(FUNCHECK(f)); AVER(FUNCHECK(f));
/* p and s are arbitrary closures and can't be checked */ /* p and s are arbitrary closures and can't be checked */
awl = Pool2AWL(pool); awl = PoolAWL(pool);
AVERT(AWL, awl); AVERT(AWL, awl);
awlseg = Seg2AWLSeg(seg); awlseg = Seg2AWLSeg(seg);
AVERT(AWLSeg, awlseg); AVERT(AWLSeg, awlseg);
@ -1281,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 */ /* AWLPoolClass -- the class definition */
DEFINE_POOL_CLASS(AWLPoolClass, this) DEFINE_POOL_CLASS(AWLPoolClass, this)
@ -1305,6 +1334,8 @@ DEFINE_POOL_CLASS(AWLPoolClass, this)
this->fixEmergency = AWLFix; this->fixEmergency = AWLFix;
this->reclaim = AWLReclaim; this->reclaim = AWLReclaim;
this->walk = AWLWalk; this->walk = AWLWalk;
this->totalSize = AWLTotalSize;
this->freeSize = AWLFreeSize;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -1321,9 +1352,9 @@ ATTRIBUTE_UNUSED
static Bool AWLCheck(AWL awl) static Bool AWLCheck(AWL awl)
{ {
CHECKS(AWL, awl); CHECKS(AWL, awl);
CHECKD(Pool, &awl->poolStruct); CHECKD(Pool, AWLPool(awl));
CHECKL(awl->poolStruct.class == AWLPoolClassGet()); CHECKL(AWLPool(awl)->class == AWLPoolClassGet());
CHECKL(AWLGrainsSize(awl, (Count)1) == awl->poolStruct.alignment); CHECKL(AWLGrainsSize(awl, (Count)1) == PoolAlignment(AWLPool(awl)));
/* Nothing to check about succAccesses. */ /* Nothing to check about succAccesses. */
CHECKL(FUNCHECK(awl->findDependent)); CHECKL(FUNCHECK(awl->findDependent));
/* Don't bother to check stats. */ /* Don't bother to check stats. */

View file

@ -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 */ /* LOPoolClass -- the class definition */
DEFINE_POOL_CLASS(LOPoolClass, this) DEFINE_POOL_CLASS(LOPoolClass, this)
@ -814,6 +842,8 @@ DEFINE_POOL_CLASS(LOPoolClass, this)
this->fixEmergency = LOFix; this->fixEmergency = LOFix;
this->reclaim = LOReclaim; this->reclaim = LOReclaim;
this->walk = LOWalk; this->walk = LOWalk;
this->totalSize = LOTotalSize;
this->freeSize = LOFreeSize;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -832,10 +862,10 @@ ATTRIBUTE_UNUSED
static Bool LOCheck(LO lo) static Bool LOCheck(LO lo)
{ {
CHECKS(LO, lo); CHECKS(LO, lo);
CHECKD(Pool, &lo->poolStruct); CHECKD(Pool, LOPool(lo));
CHECKL(lo->poolStruct.class == EnsureLOPoolClass()); CHECKL(LOPool(lo)->class == EnsureLOPoolClass());
CHECKL(ShiftCheck(lo->alignShift)); CHECKL(ShiftCheck(lo->alignShift));
CHECKL(LOGrainsSize(lo, (Count)1) == PoolAlignment(&lo->poolStruct)); CHECKL(LOGrainsSize(lo, (Count)1) == PoolAlignment(LOPool(lo)));
CHECKD(PoolGen, &lo->pgen); CHECKD(PoolGen, &lo->pgen);
return TRUE; return TRUE;
} }

View file

@ -60,13 +60,6 @@ typedef struct MFSHeaderStruct {
#define UNIT_MIN sizeof(HeaderStruct) #define UNIT_MIN sizeof(HeaderStruct)
Pool (MFSPool)(MFS mfs)
{
AVERT(MFS, mfs);
return &mfs->poolStruct;
}
/* MFSVarargs -- decode obsolete varargs */ /* MFSVarargs -- decode obsolete varargs */
static void MFSVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) static void MFSVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
@ -123,6 +116,8 @@ static Res MFSInit(Pool pool, ArgList args)
mfs->unitSize = unitSize; mfs->unitSize = unitSize;
mfs->freeList = NULL; mfs->freeList = NULL;
mfs->tractList = NULL; mfs->tractList = NULL;
mfs->total = 0;
mfs->free = 0;
mfs->sig = MFSSig; mfs->sig = MFSSig;
AVERT(MFS, mfs); AVERT(MFS, mfs);
@ -199,6 +194,10 @@ void MFSExtend(Pool pool, Addr base, Size size)
TractSetP(tract, (void *)mfs->tractList); TractSetP(tract, (void *)mfs->tractList);
mfs->tractList = tract; mfs->tractList = tract;
/* Update accounting */
mfs->total += size;
mfs->free += size;
/* Sew together all the new empty units in the region, working down */ /* 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 */ /* from the top so that they are in ascending order of address on the */
/* free list. */ /* free list. */
@ -272,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. */ /* Detach the first free unit from the free list and return its address. */
mfs->freeList = f->next; mfs->freeList = f->next;
AVER(mfs->free >= mfs->unitSize);
mfs->free -= mfs->unitSize;
*pReturn = (Addr)f; *pReturn = (Addr)f;
return ResOK; return ResOK;
@ -300,10 +301,39 @@ static void MFSFree(Pool pool, Addr old, Size size)
h = (Header)old; h = (Header)old;
h->next = mfs->freeList; h->next = mfs->freeList;
mfs->freeList = h; mfs->freeList = h;
mfs->free += mfs->unitSize;
} }
static Res MFSDescribe(Pool pool, mps_lib_FILE *stream) /* 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;
}
static Res MFSDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
MFS mfs; MFS mfs;
Res res; Res res;
@ -314,7 +344,7 @@ static Res MFSDescribe(Pool pool, mps_lib_FILE *stream)
AVER(stream != NULL); AVER(stream != NULL);
res = WriteF(stream, res = WriteF(stream, depth,
"unrounded unit size $W\n", (WriteFW)mfs->unroundedUnitSize, "unrounded unit size $W\n", (WriteFW)mfs->unroundedUnitSize,
"unit size $W\n", (WriteFW)mfs->unitSize, "unit size $W\n", (WriteFW)mfs->unitSize,
"extent size $W\n", (WriteFW)mfs->extendBy, "extent size $W\n", (WriteFW)mfs->extendBy,
@ -338,6 +368,8 @@ DEFINE_POOL_CLASS(MFSPoolClass, this)
this->finish = MFSFinish; this->finish = MFSFinish;
this->alloc = MFSAlloc; this->alloc = MFSAlloc;
this->free = MFSFree; this->free = MFSFree;
this->totalSize = MFSTotalSize;
this->freeSize = MFSFreeSize;
this->describe = MFSDescribe; this->describe = MFSDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -360,18 +392,20 @@ Bool MFSCheck(MFS mfs)
Arena arena; Arena arena;
CHECKS(MFS, mfs); CHECKS(MFS, mfs);
CHECKD(Pool, &mfs->poolStruct); CHECKD(Pool, MFSPool(mfs));
CHECKL(mfs->poolStruct.class == EnsureMFSPoolClass()); CHECKL(MFSPool(mfs)->class == EnsureMFSPoolClass());
CHECKL(mfs->unitSize >= UNIT_MIN); CHECKL(mfs->unitSize >= UNIT_MIN);
CHECKL(mfs->extendBy >= UNIT_MIN); CHECKL(mfs->extendBy >= UNIT_MIN);
CHECKL(BoolCheck(mfs->extendSelf)); CHECKL(BoolCheck(mfs->extendSelf));
arena = PoolArena(&mfs->poolStruct); arena = PoolArena(MFSPool(mfs));
CHECKL(SizeIsArenaGrains(mfs->extendBy, arena)); CHECKL(SizeIsArenaGrains(mfs->extendBy, arena));
CHECKL(SizeAlignUp(mfs->unroundedUnitSize, mfs->poolStruct.alignment) == CHECKL(SizeAlignUp(mfs->unroundedUnitSize, PoolAlignment(MFSPool(mfs))) ==
mfs->unitSize); mfs->unitSize);
if(mfs->tractList != NULL) { if(mfs->tractList != NULL) {
CHECKD_NOSIG(Tract, mfs->tractList); CHECKD_NOSIG(Tract, mfs->tractList);
} }
CHECKL(mfs->free <= mfs->total);
CHECKL((mfs->total - mfs->free) % mfs->unitSize == 0);
return TRUE; return TRUE;
} }

View file

@ -33,11 +33,11 @@
typedef struct MFSStruct *MFS; typedef struct MFSStruct *MFS;
#define MFSPool(mfs) (&(mfs)->poolStruct)
extern PoolClass PoolClassMFS(void); extern PoolClass PoolClassMFS(void);
extern Bool MFSCheck(MFS mfs); extern Bool MFSCheck(MFS mfs);
extern Pool (MFSPool)(MFS mfs);
extern const struct mps_key_s _mps_key_MFSExtendSelf; extern const struct mps_key_s _mps_key_MFSExtendSelf;
#define MFSExtendSelf (&_mps_key_MFSExtendSelf) #define MFSExtendSelf (&_mps_key_MFSExtendSelf)

View file

@ -119,8 +119,8 @@ typedef struct MRGStruct {
Sig sig; /* <code/mps.h#sig> */ Sig sig; /* <code/mps.h#sig> */
} MRGStruct; } MRGStruct;
#define Pool2MRG(pool) PARENT(MRGStruct, poolStruct, pool) #define PoolMRG(pool) PARENT(MRGStruct, poolStruct, pool)
#define MRG2Pool(mrg) (&(mrg)->poolStruct) #define MRGPool(mrg) (&(mrg)->poolStruct)
/* MRGCheck -- check an MRG pool */ /* MRGCheck -- check an MRG pool */
@ -129,12 +129,12 @@ ATTRIBUTE_UNUSED
static Bool MRGCheck(MRG mrg) static Bool MRGCheck(MRG mrg)
{ {
CHECKS(MRG, mrg); CHECKS(MRG, mrg);
CHECKD(Pool, &mrg->poolStruct); CHECKD(Pool, MRGPool(mrg));
CHECKL(MRG2Pool(mrg)->class == PoolClassMRG()); CHECKL(MRGPool(mrg)->class == PoolClassMRG());
CHECKD_NOSIG(Ring, &mrg->entryRing); CHECKD_NOSIG(Ring, &mrg->entryRing);
CHECKD_NOSIG(Ring, &mrg->freeRing); CHECKD_NOSIG(Ring, &mrg->freeRing);
CHECKD_NOSIG(Ring, &mrg->refRing); CHECKD_NOSIG(Ring, &mrg->refRing);
CHECKL(mrg->extendBy == ArenaGrainSize(PoolArena(MRG2Pool(mrg)))); CHECKL(mrg->extendBy == ArenaGrainSize(PoolArena(MRGPool(mrg))));
return TRUE; return TRUE;
} }
@ -225,7 +225,7 @@ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Seg, seg); AVERT(Seg, seg);
linkseg = Seg2LinkSeg(seg); linkseg = Seg2LinkSeg(seg);
AVERT(Pool, pool); AVERT(Pool, pool);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
/* no useful checks for base and size */ /* no useful checks for base and size */
AVERT(Bool, reservoirPermit); AVERT(Bool, reservoirPermit);
@ -268,7 +268,7 @@ static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Seg, seg); AVERT(Seg, seg);
refseg = Seg2RefSeg(seg); refseg = Seg2RefSeg(seg);
AVERT(Pool, pool); AVERT(Pool, pool);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
/* no useful checks for base and size */ /* no useful checks for base and size */
AVERT(Bool, reservoirPermit); AVERT(Bool, reservoirPermit);
@ -360,7 +360,7 @@ static RefPart MRGRefPartOfLink(Link link, Arena arena)
linkBase = (Link)SegBase(seg); linkBase = (Link)SegBase(seg);
AVER(link >= linkBase); AVER(link >= linkBase);
indx = (Index)(link - linkBase); indx = (Index)(link - linkBase);
AVER(indx < MRGGuardiansPerSeg(Pool2MRG(SegPool(seg)))); AVER(indx < MRGGuardiansPerSeg(PoolMRG(SegPool(seg))));
return refPartOfIndex(linkseg->refSeg, indx); return refPartOfIndex(linkseg->refSeg, indx);
} }
@ -389,7 +389,7 @@ static Link MRGLinkOfRefPart(RefPart refPart, Arena arena)
refPartBase = (RefPart)SegBase(seg); refPartBase = (RefPart)SegBase(seg);
AVER(refPart >= refPartBase); AVER(refPart >= refPartBase);
indx = refPart - refPartBase; indx = refPart - refPartBase;
AVER(indx < MRGGuardiansPerSeg(Pool2MRG(SegPool(seg)))); AVER(indx < MRGGuardiansPerSeg(PoolMRG(SegPool(seg))));
return linkOfIndex(refseg->linkSeg, indx); return linkOfIndex(refseg->linkSeg, indx);
} }
@ -408,7 +408,7 @@ static void MRGGuardianInit(MRG mrg, Link link, RefPart refPart)
link->state = MRGGuardianFREE; link->state = MRGGuardianFREE;
RingAppend(&mrg->freeRing, &link->the.linkRing); RingAppend(&mrg->freeRing, &link->the.linkRing);
/* <design/poolmrg/#free.overwrite> */ /* <design/poolmrg/#free.overwrite> */
MRGRefPartSetRef(PoolArena(&mrg->poolStruct), refPart, 0); MRGRefPartSetRef(PoolArena(MRGPool(mrg)), refPart, 0);
} }
@ -434,7 +434,7 @@ static void MRGMessageDelete(Message message)
link = linkOfMessage(message); link = linkOfMessage(message);
AVER(link->state == MRGGuardianFINAL); AVER(link->state == MRGGuardianFINAL);
MessageFinish(message); MessageFinish(message);
MRGGuardianInit(Pool2MRG(pool), link, MRGRefPartOfLink(link, arena)); MRGGuardianInit(PoolMRG(pool), link, MRGRefPartOfLink(link, arena));
} }
@ -516,7 +516,7 @@ static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg,
AVER(refSegReturn != NULL); AVER(refSegReturn != NULL);
pool = MRG2Pool(mrg); pool = MRGPool(mrg);
arena = PoolArena(pool); arena = PoolArena(pool);
nGuardians = MRGGuardiansPerSeg(mrg); nGuardians = MRGGuardiansPerSeg(mrg);
@ -566,7 +566,7 @@ static void MRGFinalize(Arena arena, MRGLinkSeg linkseg, Index indx)
Link link; Link link;
Message message; Message message;
AVER(indx < MRGGuardiansPerSeg(Pool2MRG(SegPool(LinkSeg2Seg(linkseg))))); AVER(indx < MRGGuardiansPerSeg(PoolMRG(SegPool(LinkSeg2Seg(linkseg)))));
link = linkOfIndex(linkseg, indx); link = linkOfIndex(linkseg, indx);
@ -597,7 +597,7 @@ static Res MRGRefSegScan(ScanState ss, MRGRefSeg refseg, MRG mrg)
AVERT(MRGRefSeg, refseg); AVERT(MRGRefSeg, refseg);
AVERT(MRG, mrg); AVERT(MRG, mrg);
arena = PoolArena(MRG2Pool(mrg)); arena = PoolArena(MRGPool(mrg));
linkseg = refseg->linkSeg; linkseg = refseg->linkSeg;
nGuardians = MRGGuardiansPerSeg(mrg); nGuardians = MRGGuardiansPerSeg(mrg);
@ -638,7 +638,7 @@ static Res MRGInit(Pool pool, ArgList args)
AVERT(ArgList, args); AVERT(ArgList, args);
UNUSED(args); UNUSED(args);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
RingInit(&mrg->entryRing); RingInit(&mrg->entryRing);
RingInit(&mrg->freeRing); RingInit(&mrg->freeRing);
@ -660,7 +660,7 @@ static void MRGFinish(Pool pool)
Ring node, nextNode; Ring node, nextNode;
AVERT(Pool, pool); AVERT(Pool, pool);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
/* .finish.ring: Before destroying the segments, we isolate the */ /* .finish.ring: Before destroying the segments, we isolate the */
@ -714,7 +714,7 @@ Res MRGRegister(Pool pool, Ref ref)
AVERT(Pool, pool); AVERT(Pool, pool);
AVER(ref != 0); AVER(ref != 0);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
arena = PoolArena(pool); arena = PoolArena(pool);
@ -757,7 +757,7 @@ Res MRGDeregister(Pool pool, Ref obj)
AVERT(Pool, pool); AVERT(Pool, pool);
/* Can't check obj */ /* Can't check obj */
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
nGuardians = MRGGuardiansPerSeg(mrg); nGuardians = MRGGuardiansPerSeg(mrg);
arena = PoolArena(pool); arena = PoolArena(pool);
@ -796,7 +796,7 @@ Res MRGDeregister(Pool pool, Ref obj)
* This could be improved by implementing MRGSegDescribe * This could be improved by implementing MRGSegDescribe
* and having MRGDescribe iterate over all the pool's segments. * and having MRGDescribe iterate over all the pool's segments.
*/ */
static Res MRGDescribe(Pool pool, mps_lib_FILE *stream) static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
MRG mrg; MRG mrg;
Arena arena; Arena arena;
@ -805,20 +805,27 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream)
Res res; Res res;
if (!TESTT(Pool, pool)) return ResFAIL; if (!TESTT(Pool, pool)) return ResFAIL;
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
if (!TESTT(MRG, mrg)) return ResFAIL; if (!TESTT(MRG, mrg)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
arena = PoolArena(pool); arena = PoolArena(pool);
res = WriteF(stream, " extendBy $W\n", mrg->extendBy, NULL); res = WriteF(stream, depth, "extendBy $W\n", mrg->extendBy, NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, " Entry queue:\n", NULL); res = WriteF(stream, depth, "Entry queue:\n", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
RING_FOR(node, &mrg->entryRing, nextNode) { RING_FOR(node, &mrg->entryRing, nextNode) {
Bool outsideShield = !arena->insideShield;
refPart = MRGRefPartOfLink(linkOfRing(node), arena); refPart = MRGRefPartOfLink(linkOfRing(node), arena);
res = WriteF(stream, " at $A Ref $A\n", if (outsideShield) {
ShieldEnter(arena);
}
res = WriteF(stream, depth, "at $A Ref $A\n",
(WriteFA)refPart, (WriteFA)MRGRefPartRef(arena, refPart), (WriteFA)refPart, (WriteFA)MRGRefPartRef(arena, refPart),
NULL); NULL);
if (outsideShield) {
ShieldLeave(arena);
}
if (res != ResOK) return res; if (res != ResOK) return res;
} }
@ -836,7 +843,7 @@ static Res MRGScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVERT(Pool, pool); AVERT(Pool, pool);
AVERT(Seg, seg); AVERT(Seg, seg);
mrg = Pool2MRG(pool); mrg = PoolMRG(pool);
AVERT(MRG, mrg); AVERT(MRG, mrg);
AVER(SegRankSet(seg) == RankSetSingle(RankFINAL)); /* .improve.rank */ AVER(SegRankSet(seg) == RankSetSingle(RankFINAL)); /* .improve.rank */

View file

@ -38,7 +38,7 @@ SRCID(poolmv, "$Id$");
#define mvSpanPool(mv) MFSPool(&(mv)->spanPoolStruct) #define mvSpanPool(mv) MFSPool(&(mv)->spanPoolStruct)
#define Pool2MV(pool) PARENT(MVStruct, poolStruct, pool) #define PoolMV(pool) PARENT(MVStruct, poolStruct, pool)
/* MVDebug -- MV Debug pool class */ /* MVDebug -- MV Debug pool class */
@ -116,7 +116,7 @@ typedef struct MVSpanStruct {
MVBlockStruct base; /* sentinel at base of span */ MVBlockStruct base; /* sentinel at base of span */
MVBlockStruct limit; /* sentinel at limit of span */ MVBlockStruct limit; /* sentinel at limit of span */
MVBlock blocks; /* allocated blocks */ MVBlock blocks; /* allocated blocks */
Size space; /* total free space in span */ Size free; /* free space in span */
Size largest; /* .design.largest */ Size largest; /* .design.largest */
Bool largestKnown; /* .design.largest */ Bool largestKnown; /* .design.largest */
unsigned blockCount; /* number of blocks on chain */ unsigned blockCount; /* number of blocks on chain */
@ -160,11 +160,11 @@ static Bool MVSpanCheck(MVSpan span)
/* The sentinels mustn't overlap. */ /* The sentinels mustn't overlap. */
CHECKL(span->base.limit <= span->limit.base); CHECKL(span->base.limit <= span->limit.base);
/* The free space can't be more than the gap between the sentinels. */ /* 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)); CHECKL(BoolCheck(span->largestKnown));
if (span->largestKnown) { /* .design.largest */ if (span->largestKnown) { /* .design.largest */
CHECKL(span->largest <= span->space); CHECKL(span->largest <= span->free);
/* at least this much is free */ /* at least this much is free */
} else { } else {
CHECKL(span->largest == SpanSize(span)+1); CHECKL(span->largest == SpanSize(span)+1);
@ -244,7 +244,7 @@ static Res MVInit(Pool pool, ArgList args)
AVER(extendBy <= maxSize); AVER(extendBy <= maxSize);
pool->alignment = align; pool->alignment = align;
mv = Pool2MV(pool); mv = PoolMV(pool);
arena = PoolArena(pool); arena = PoolArena(pool);
/* At 100% fragmentation we will need one block descriptor for every other */ /* At 100% fragmentation we will need one block descriptor for every other */
@ -257,7 +257,7 @@ static Res MVInit(Pool pool, ArgList args)
MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_BEGIN(piArgs) {
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, blockExtendBy); MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, blockExtendBy);
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(MVBlockStruct)); MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(MVBlockStruct));
res = PoolInit(&mv->blockPoolStruct.poolStruct, arena, PoolClassMFS(), piArgs); res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs); } MPS_ARGS_END(piArgs);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -267,7 +267,7 @@ static Res MVInit(Pool pool, ArgList args)
MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_BEGIN(piArgs) {
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, spanExtendBy); MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, spanExtendBy);
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(MVSpanStruct)); MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(MVSpanStruct));
res = PoolInit(&mv->spanPoolStruct.poolStruct, arena, PoolClassMFS(), piArgs); res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs); } MPS_ARGS_END(piArgs);
if(res != ResOK) if(res != ResOK)
return res; return res;
@ -277,7 +277,7 @@ static Res MVInit(Pool pool, ArgList args)
mv->maxSize = maxSize; mv->maxSize = maxSize;
RingInit(&mv->spans); RingInit(&mv->spans);
mv->space = 0; mv->free = 0;
mv->lost = 0; mv->lost = 0;
mv->sig = MVSig; mv->sig = MVSig;
@ -296,7 +296,7 @@ static void MVFinish(Pool pool)
MVSpan span; MVSpan span;
AVERT(Pool, pool); AVERT(Pool, pool);
mv = Pool2MV(pool); mv = PoolMV(pool);
AVERT(MV, mv); AVERT(MV, mv);
/* Destroy all the spans attached to the pool. */ /* Destroy all the spans attached to the pool. */
@ -309,8 +309,8 @@ static void MVFinish(Pool pool)
mv->sig = SigInvalid; mv->sig = SigInvalid;
PoolFinish(&mv->blockPoolStruct.poolStruct); PoolFinish(mvBlockPool(mv));
PoolFinish(&mv->spanPoolStruct.poolStruct); PoolFinish(mvSpanPool(mv));
} }
@ -368,7 +368,7 @@ static Bool MVSpanAlloc(Addr *addrReturn, MVSpan span, Size size,
span->largest = SpanSize(span) + 1; /* .design.largest */ span->largest = SpanSize(span) + 1; /* .design.largest */
} }
span->space -= size; span->free -= size;
*addrReturn = new; *addrReturn = new;
return TRUE; return TRUE;
} }
@ -484,7 +484,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool)
AVERT(MVBlock, block); AVERT(MVBlock, block);
span->space += AddrOffset(base, limit); span->free += AddrOffset(base, limit);
if (freeAreaSize > span->largest) { /* .design.largest */ if (freeAreaSize > span->largest) { /* .design.largest */
AVER(span->largestKnown); AVER(span->largestKnown);
@ -521,23 +521,23 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
AVER(pReturn != NULL); AVER(pReturn != NULL);
AVERT(Pool, pool); AVERT(Pool, pool);
mv = Pool2MV(pool); mv = PoolMV(pool);
AVERT(MV, mv); AVERT(MV, mv);
AVER(size > 0); AVER(size > 0);
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
size = SizeAlignUp(size, pool->alignment); size = SizeAlignUp(size, pool->alignment);
if(size <= mv->space) { if(size <= mv->free) {
spans = &mv->spans; spans = &mv->spans;
RING_FOR(node, spans, nextNode) { RING_FOR(node, spans, nextNode) {
span = RING_ELT(MVSpan, spans, node); span = RING_ELT(MVSpan, spans, node);
if((size <= span->largest) && /* .design.largest.alloc */ if((size <= span->largest) && /* .design.largest.alloc */
(size <= span->space)) { (size <= span->free)) {
Addr new; Addr new;
if(MVSpanAlloc(&new, span, size, mvBlockPool(mv))) { if(MVSpanAlloc(&new, span, size, mvBlockPool(mv))) {
mv->space -= size; mv->free -= size;
AVER(AddrIsAligned(new, pool->alignment)); AVER(AddrIsAligned(new, pool->alignment));
*pReturn = new; *pReturn = new;
return ResOK; return ResOK;
@ -593,20 +593,20 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
RingInit(&span->spans); RingInit(&span->spans);
span->base.base = span->base.limit = base; span->base.base = span->base.limit = base;
span->limit.base = span->limit.limit = limit; 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->limit.next = NULL;
span->base.next = &span->limit; span->base.next = &span->limit;
span->blocks = &span->base; span->blocks = &span->base;
span->blockCount = 2; span->blockCount = 2;
span->base.limit = AddrAdd(span->base.limit, size); span->base.limit = AddrAdd(span->base.limit, size);
span->space -= size; span->free -= size;
span->largest = span->space; span->largest = span->free;
span->largestKnown = TRUE; span->largestKnown = TRUE;
span->sig = MVSpanSig; span->sig = MVSpanSig;
AVERT(MVSpan, span); AVERT(MVSpan, span);
mv->space += span->space; mv->free += span->free;
RingInsert(&mv->spans, &span->spans); RingInsert(&mv->spans, &span->spans);
/* use RingInsert so that we examine this new span first when allocating */ /* use RingInsert so that we examine this new span first when allocating */
@ -627,7 +627,7 @@ static void MVFree(Pool pool, Addr old, Size size)
Tract tract = NULL; /* suppress "may be used uninitialized" */ Tract tract = NULL; /* suppress "may be used uninitialized" */
AVERT(Pool, pool); AVERT(Pool, pool);
mv = Pool2MV(pool); mv = PoolMV(pool);
AVERT(MV, mv); AVERT(MV, mv);
AVER(old != (Addr)0); AVER(old != (Addr)0);
@ -655,16 +655,16 @@ static void MVFree(Pool pool, Addr old, Size size)
if(res != ResOK) if(res != ResOK)
mv->lost += size; mv->lost += size;
else else
mv->space += size; mv->free += size;
/* free space should be less than total space */ /* free space should be less than total space */
AVER(span->space <= SpanInsideSentinels(span)); AVER(span->free <= SpanInsideSentinels(span));
if(span->space == SpanSize(span)) { /* the whole span is free */ if(span->free == SpanSize(span)) { /* the whole span is free */
AVER(span->blockCount == 2); AVER(span->blockCount == 2);
/* both blocks are the trivial sentinel blocks */ /* both blocks are the trivial sentinel blocks */
AVER(span->base.limit == span->base.base); AVER(span->base.limit == span->base.base);
AVER(span->limit.limit == span->limit.base); AVER(span->limit.limit == span->limit.base);
mv->space -= span->space; mv->free -= span->free;
ArenaFree(TractBase(span->tract), span->size, pool); ArenaFree(TractBase(span->tract), span->size, pool);
RingRemove(&span->spans); RingRemove(&span->spans);
RingFinish(&span->spans); RingFinish(&span->spans);
@ -680,14 +680,59 @@ static PoolDebugMixin MVDebugMixin(Pool pool)
MV mv; MV mv;
AVERT(Pool, pool); AVERT(Pool, pool);
mv = Pool2MV(pool); mv = PoolMV(pool);
AVERT(MV, mv); AVERT(MV, mv);
/* Can't check MVDebug, because this is called during MVDebug init */ /* Can't check MVDebug, because this is called during MVDebug init */
return &(MV2MVDebug(mv)->debug); return &(MV2MVDebug(mv)->debug);
} }
static Res MVDescribe(Pool pool, mps_lib_FILE *stream) /* 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; Res res;
MV mv; MV mv;
@ -698,11 +743,11 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream)
Ring spans, node = NULL, nextNode; /* gcc whinge stop */ Ring spans, node = NULL, nextNode; /* gcc whinge stop */
if(!TESTT(Pool, pool)) return ResFAIL; if(!TESTT(Pool, pool)) return ResFAIL;
mv = Pool2MV(pool); mv = PoolMV(pool);
if(!TESTT(MV, mv)) return ResFAIL; if(!TESTT(MV, mv)) return ResFAIL;
if(stream == NULL) return ResFAIL; if(stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"blockPool $P ($U)\n", "blockPool $P ($U)\n",
(WriteFP)mvBlockPool(mv), (WriteFU)mvBlockPool(mv)->serial, (WriteFP)mvBlockPool(mv), (WriteFU)mvBlockPool(mv)->serial,
"spanPool $P ($U)\n", "spanPool $P ($U)\n",
@ -710,38 +755,11 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream)
"extendBy $W\n", (WriteFW)mv->extendBy, "extendBy $W\n", (WriteFW)mv->extendBy,
"avgSize $W\n", (WriteFW)mv->avgSize, "avgSize $W\n", (WriteFW)mv->avgSize,
"maxSize $W\n", (WriteFW)mv->maxSize, "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); NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
res = WriteF(stream, " Spans\n", NULL);
if(res != ResOK) return res;
spans = &mv->spans;
RING_FOR(node, spans, nextNode) {
span = RING_ELT(MVSpan, spans, node);
AVERT(MVSpan, span);
res = WriteF(stream,
" span $P", (WriteFP)span,
" tract $P", (WriteFP)span->tract,
" space $W", (WriteFW)span->space,
" blocks $U", (WriteFU)span->blockCount,
" largest ",
NULL);
if(res != ResOK) return res;
if (span->largestKnown) /* .design.largest */
res = WriteF(stream, "$W\n", (WriteFW)span->largest, NULL);
else
res = WriteF(stream, "unknown\n", NULL);
if(res != ResOK) return res;
}
res = WriteF(stream, " Span allocation maps\n", NULL);
if(res != ResOK) return res;
step = pool->alignment; step = pool->alignment;
length = 0x40 * step; length = 0x40 * step;
@ -750,13 +768,28 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream)
Addr i, j; Addr i, j;
MVBlock block; MVBlock block;
span = RING_ELT(MVSpan, spans, node); span = RING_ELT(MVSpan, spans, node);
res = WriteF(stream, " MVSpan $P\n", (WriteFP)span, NULL); res = WriteF(stream, depth, "MVSpan $P {\n", (WriteFP)span, NULL);
if(res != ResOK) return res;
res = WriteF(stream, depth + 2,
"span $P\n", (WriteFP)span,
"tract $P\n", (WriteFP)span->tract,
"free $W\n", (WriteFW)span->free,
"blocks $U\n", (WriteFU)span->blockCount,
"largest ",
NULL);
if(res != ResOK) return res;
if (span->largestKnown) /* .design.largest */
res = WriteF(stream, 0, "$W\n", (WriteFW)span->largest, NULL);
else
res = WriteF(stream, 0, "unknown\n", NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
block = span->blocks; block = span->blocks;
for(i = span->base.base; i < span->limit.limit; i = AddrAdd(i, length)) { for(i = span->base.base; i < span->limit.limit; i = AddrAdd(i, length)) {
res = WriteF(stream, " $A ", i, NULL); res = WriteF(stream, depth + 2, "$A ", i, NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
for(j = i; for(j = i;
@ -779,12 +812,14 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream)
c = ']'; c = ']';
else /* j > block->base && j < block->limit */ else /* j > block->base && j < block->limit */
c = '='; c = '=';
res = WriteF(stream, "$C", c, NULL); res = WriteF(stream, 0, "$C", c, NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
} }
res = WriteF(stream, "\n", NULL); res = WriteF(stream, 0, "\n", NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
} }
res = WriteF(stream, depth, "} MVSpan $P\n", (WriteFP)span, NULL);
if(res != ResOK) return res;
} }
return ResOK; return ResOK;
@ -805,6 +840,8 @@ DEFINE_POOL_CLASS(MVPoolClass, this)
this->finish = MVFinish; this->finish = MVFinish;
this->alloc = MVAlloc; this->alloc = MVAlloc;
this->free = MVFree; this->free = MVFree;
this->totalSize = MVTotalSize;
this->freeSize = MVFreeSize;
this->describe = MVDescribe; this->describe = MVDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -846,65 +883,13 @@ 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 */ /* MVCheck -- check the consistency of an MV structure */
Bool MVCheck(MV mv) Bool MVCheck(MV mv)
{ {
CHECKS(MV, mv); CHECKS(MV, mv);
CHECKD(Pool, &mv->poolStruct); CHECKD(Pool, MVPool(mv));
CHECKL(IsSubclassPoly(mv->poolStruct.class, EnsureMVPoolClass())); CHECKL(IsSubclassPoly(MVPool(mv)->class, EnsureMVPoolClass()));
CHECKD(MFS, &mv->blockPoolStruct); CHECKD(MFS, &mv->blockPoolStruct);
CHECKD(MFS, &mv->spanPoolStruct); CHECKD(MFS, &mv->spanPoolStruct);
CHECKL(mv->extendBy > 0); CHECKL(mv->extendBy > 0);

View file

@ -26,7 +26,7 @@ extern PoolClass PoolClassMV(void);
extern Bool MVCheck(MV mv); extern Bool MVCheck(MV mv);
#define MV2Pool(mv) (&(mv)->poolStruct) #define MVPool(mv) (&(mv)->poolStruct)
#endif /* poolmv_h */ #endif /* poolmv_h */

View file

@ -39,7 +39,9 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
Bool withReservoirPermit); Bool withReservoirPermit);
static void MVTBufferEmpty(Pool pool, Buffer buffer, Addr base, Addr limit); static void MVTBufferEmpty(Pool pool, Buffer buffer, Addr base, Addr limit);
static void MVTFree(Pool pool, Addr base, Size size); static void MVTFree(Pool pool, Addr base, Size size);
static Res MVTDescribe(Pool pool, mps_lib_FILE *stream); 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, static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
Bool withReservoirPermit); Bool withReservoirPermit);
@ -52,9 +54,9 @@ static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
MVT mvt, Size min); MVT mvt, Size min);
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena); static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena);
static ABQ MVTABQ(MVT mvt); static ABQ MVTABQ(MVT mvt);
static Land MVTCBS(MVT mvt); static Land MVTFreePrimary(MVT mvt);
static Land MVTFreelist(MVT mvt); static Land MVTFreeSecondary(MVT mvt);
static Land MVTFailover(MVT mvt); static Land MVTFreeLand(MVT mvt);
/* Types */ /* Types */
@ -145,14 +147,16 @@ DEFINE_POOL_CLASS(MVTPoolClass, this)
this->free = MVTFree; this->free = MVTFree;
this->bufferFill = MVTBufferFill; this->bufferFill = MVTBufferFill;
this->bufferEmpty = MVTBufferEmpty; this->bufferEmpty = MVTBufferEmpty;
this->totalSize = MVTTotalSize;
this->freeSize = MVTFreeSize;
this->describe = MVTDescribe; this->describe = MVTDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
/* Macros */ /* Macros */
#define Pool2MVT(pool) PARENT(MVTStruct, poolStruct, pool) #define PoolMVT(pool) PARENT(MVTStruct, poolStruct, pool)
#define MVT2Pool(mvt) (&(mvt)->poolStruct) #define MVTPool(mvt) (&(mvt)->poolStruct)
/* Accessors */ /* Accessors */
@ -164,21 +168,21 @@ static ABQ MVTABQ(MVT mvt)
} }
static Land MVTCBS(MVT mvt) static Land MVTFreePrimary(MVT mvt)
{ {
return &mvt->cbsStruct.landStruct; return CBSLand(&mvt->cbsStruct);
} }
static Land MVTFreelist(MVT mvt) static Land MVTFreeSecondary(MVT mvt)
{ {
return &mvt->flStruct.landStruct; return FreelistLand(&mvt->flStruct);
} }
static Land MVTFailover(MVT mvt) static Land MVTFreeLand(MVT mvt)
{ {
return &mvt->foStruct.landStruct; return FailoverLand(&mvt->foStruct);
} }
@ -233,7 +237,7 @@ static Res MVTInit(Pool pool, ArgList args)
ArgStruct arg; ArgStruct arg;
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
/* can't AVERT mvt, yet */ /* can't AVERT mvt, yet */
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Arena, arena); AVERT(Arena, arena);
@ -276,28 +280,28 @@ static Res MVTInit(Pool pool, ArgList args)
if (abqDepth < 3) if (abqDepth < 3)
abqDepth = 3; abqDepth = 3;
res = LandInit(MVTCBS(mvt), CBSFastLandClassGet(), arena, align, mvt, res = LandInit(MVTFreePrimary(mvt), CBSFastLandClassGet(), arena, align, mvt,
mps_args_none); mps_args_none);
if (res != ResOK) if (res != ResOK)
goto failCBS; goto failFreePrimaryInit;
res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt, res = LandInit(MVTFreeSecondary(mvt), FreelistLandClassGet(), arena, align,
mps_args_none); mvt, mps_args_none);
if (res != ResOK) if (res != ResOK)
goto failFreelist; goto failFreeSecondaryInit;
MPS_ARGS_BEGIN(foArgs) { MPS_ARGS_BEGIN(foArgs) {
MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTCBS(mvt)); MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTFreePrimary(mvt));
MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreelist(mvt)); MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreeSecondary(mvt));
res = LandInit(MVTFailover(mvt), FailoverLandClassGet(), arena, align, mvt, res = LandInit(MVTFreeLand(mvt), FailoverLandClassGet(), arena, align, mvt,
foArgs); foArgs);
} MPS_ARGS_END(foArgs); } MPS_ARGS_END(foArgs);
if (res != ResOK) if (res != ResOK)
goto failFailover; goto failFreeLandInit;
res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct)); res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
if (res != ResOK) if (res != ResOK)
goto failABQ; goto failABQInit;
pool->alignment = align; pool->alignment = align;
mvt->reuseSize = reuseSize; mvt->reuseSize = reuseSize;
@ -361,13 +365,13 @@ static Res MVTInit(Pool pool, ArgList args)
reserveDepth, fragLimit); reserveDepth, fragLimit);
return ResOK; return ResOK;
failABQ: failABQInit:
LandFinish(MVTFailover(mvt)); LandFinish(MVTFreeLand(mvt));
failFailover: failFreeLandInit:
LandFinish(MVTFreelist(mvt)); LandFinish(MVTFreeSecondary(mvt));
failFreelist: failFreeSecondaryInit:
LandFinish(MVTCBS(mvt)); LandFinish(MVTFreePrimary(mvt));
failCBS: failFreePrimaryInit:
AVER(res != ResOK); AVER(res != ResOK);
return res; return res;
} }
@ -379,8 +383,8 @@ ATTRIBUTE_UNUSED
static Bool MVTCheck(MVT mvt) static Bool MVTCheck(MVT mvt)
{ {
CHECKS(MVT, mvt); CHECKS(MVT, mvt);
CHECKD(Pool, &mvt->poolStruct); CHECKD(Pool, MVTPool(mvt));
CHECKL(mvt->poolStruct.class == MVTPoolClassGet()); CHECKL(MVTPool(mvt)->class == MVTPoolClassGet());
CHECKD(CBS, &mvt->cbsStruct); CHECKD(CBS, &mvt->cbsStruct);
CHECKD(ABQ, &mvt->abqStruct); CHECKD(ABQ, &mvt->abqStruct);
CHECKD(Freelist, &mvt->flStruct); CHECKD(Freelist, &mvt->flStruct);
@ -418,7 +422,7 @@ static void MVTFinish(Pool pool)
Ring node, nextNode; Ring node, nextNode;
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
AVERT(MVT, mvt); AVERT(MVT, mvt);
arena = PoolArena(pool); arena = PoolArena(pool);
AVERT(Arena, arena); AVERT(Arena, arena);
@ -436,9 +440,9 @@ static void MVTFinish(Pool pool)
/* Finish the ABQ, Failover, Freelist and CBS structures */ /* Finish the ABQ, Failover, Freelist and CBS structures */
ABQFinish(arena, MVTABQ(mvt)); ABQFinish(arena, MVTABQ(mvt));
LandFinish(MVTFailover(mvt)); LandFinish(MVTFreeLand(mvt));
LandFinish(MVTFreelist(mvt)); LandFinish(MVTFreeSecondary(mvt));
LandFinish(MVTCBS(mvt)); LandFinish(MVTFreePrimary(mvt));
} }
@ -494,7 +498,7 @@ static Res MVTOversizeFill(Addr *baseReturn,
Addr base, limit; Addr base, limit;
Size alignedSize; Size alignedSize;
alignedSize = SizeArenaGrains(minSize, PoolArena(MVT2Pool(mvt))); alignedSize = SizeArenaGrains(minSize, PoolArena(MVTPool(mvt)));
res = MVTSegAlloc(&seg, mvt, alignedSize, withReservoirPermit); res = MVTSegAlloc(&seg, mvt, alignedSize, withReservoirPermit);
if (res != ResOK) if (res != ResOK)
@ -568,7 +572,7 @@ static void MVTOneSegOnly(Addr *baseIO, Addr *limitIO, MVT mvt, Size minSize)
base = *baseIO; base = *baseIO;
limit = *limitIO; limit = *limitIO;
arena = PoolArena(MVT2Pool(mvt)); arena = PoolArena(MVTPool(mvt));
SURELY(SegOfAddr(&seg, arena, base)); SURELY(SegOfAddr(&seg, arena, base));
segLimit = SegLimit(seg); segLimit = SegLimit(seg);
@ -690,7 +694,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(baseReturn != NULL); AVER(baseReturn != NULL);
AVER(limitReturn != NULL); AVER(limitReturn != NULL);
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
AVERT(MVT, mvt); AVERT(MVT, mvt);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(BufferIsReset(buffer)); AVER(BufferIsReset(buffer));
@ -782,7 +786,7 @@ static Bool MVTReserve(MVT mvt, Range range)
/* See <design/poolmvt/#impl.c.free.merge> */ /* See <design/poolmvt/#impl.c.free.merge> */
if (!ABQPush(MVTABQ(mvt), range)) { if (!ABQPush(MVTABQ(mvt), range)) {
Arena arena = PoolArena(MVT2Pool(mvt)); Arena arena = PoolArena(MVTPool(mvt));
RangeStruct oldRange; RangeStruct oldRange;
/* We just failed to push, so the ABQ must be full, and so surely /* We just failed to push, so the ABQ must be full, and so surely
* the peek will succeed. */ * the peek will succeed. */
@ -816,7 +820,7 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
AVER(base < limit); AVER(base < limit);
RangeInit(&range, base, limit); RangeInit(&range, base, limit);
res = LandInsert(&newRange, MVTFailover(mvt), &range); res = LandInsert(&newRange, MVTFreeLand(mvt), &range);
if (res != ResOK) if (res != ResOK)
return res; return res;
@ -845,7 +849,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
AVER(base < limit); AVER(base < limit);
RangeInit(&range, base, limit); RangeInit(&range, base, limit);
res = LandDelete(&rangeOld, MVTFailover(mvt), &range); res = LandDelete(&rangeOld, MVTFreeLand(mvt), &range);
if (res != ResOK) if (res != ResOK)
return res; return res;
AVER(RangesNest(&rangeOld, &range)); AVER(RangesNest(&rangeOld, &range));
@ -884,7 +888,7 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer,
Res res; Res res;
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
AVERT(MVT, mvt); AVERT(MVT, mvt);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(BufferIsReady(buffer)); AVER(BufferIsReady(buffer));
@ -949,7 +953,7 @@ static void MVTFree(Pool pool, Addr base, Size size)
Addr limit; Addr limit;
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
AVERT(MVT, mvt); AVERT(MVT, mvt);
AVER(base != (Addr)0); AVER(base != (Addr)0);
AVER(size > 0); AVER(size > 0);
@ -987,20 +991,48 @@ 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 */ /* MVTDescribe -- describe an MVT pool */
static Res MVTDescribe(Pool pool, mps_lib_FILE *stream) static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
MVT mvt; MVT mvt;
if (!TESTT(Pool, pool)) return ResFAIL; if (!TESTT(Pool, pool)) return ResFAIL;
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
if (!TESTT(MVT, mvt)) return ResFAIL; if (!TESTT(MVT, mvt)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"MVT $P\n{\n", (WriteFP)mvt, "MVT $P {\n", (WriteFP)mvt,
" minSize: $U\n", (WriteFU)mvt->minSize, " minSize: $U\n", (WriteFU)mvt->minSize,
" meanSize: $U\n", (WriteFU)mvt->meanSize, " meanSize: $U\n", (WriteFU)mvt->meanSize,
" maxSize: $U\n", (WriteFU)mvt->maxSize, " maxSize: $U\n", (WriteFU)mvt->maxSize,
@ -1019,48 +1051,49 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
NULL); NULL);
if(res != ResOK) return res; if(res != ResOK) return res;
res = LandDescribe(MVTCBS(mvt), stream); res = LandDescribe(MVTFreePrimary(mvt), stream, depth + 2);
if(res != ResOK) return res; if(res != ResOK) return res;
res = LandDescribe(MVTFreelist(mvt), stream); res = LandDescribe(MVTFreeSecondary(mvt), stream, depth + 2);
if(res != ResOK) return res; if(res != ResOK) return res;
res = LandDescribe(MVTFailover(mvt), stream); res = LandDescribe(MVTFreeLand(mvt), stream, depth + 2);
if(res != ResOK) return res; if(res != ResOK) return res;
res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream); res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream,
depth + 2);
if(res != ResOK) return res; if(res != ResOK) return res;
METER_WRITE(mvt->segAllocs, stream); METER_WRITE(mvt->segAllocs, stream, depth + 2);
METER_WRITE(mvt->segFrees, stream); METER_WRITE(mvt->segFrees, stream, depth + 2);
METER_WRITE(mvt->bufferFills, stream); METER_WRITE(mvt->bufferFills, stream, depth + 2);
METER_WRITE(mvt->bufferEmpties, stream); METER_WRITE(mvt->bufferEmpties, stream, depth + 2);
METER_WRITE(mvt->poolFrees, stream); METER_WRITE(mvt->poolFrees, stream, depth + 2);
METER_WRITE(mvt->poolSize, stream); METER_WRITE(mvt->poolSize, stream, depth + 2);
METER_WRITE(mvt->poolAllocated, stream); METER_WRITE(mvt->poolAllocated, stream, depth + 2);
METER_WRITE(mvt->poolAvailable, stream); METER_WRITE(mvt->poolAvailable, stream, depth + 2);
METER_WRITE(mvt->poolUnavailable, stream); METER_WRITE(mvt->poolUnavailable, stream, depth + 2);
METER_WRITE(mvt->poolUtilization, stream); METER_WRITE(mvt->poolUtilization, stream, depth + 2);
METER_WRITE(mvt->finds, stream); METER_WRITE(mvt->finds, stream, depth + 2);
METER_WRITE(mvt->overflows, stream); METER_WRITE(mvt->overflows, stream, depth + 2);
METER_WRITE(mvt->underflows, stream); METER_WRITE(mvt->underflows, stream, depth + 2);
METER_WRITE(mvt->refills, stream); METER_WRITE(mvt->refills, stream, depth + 2);
METER_WRITE(mvt->refillPushes, stream); METER_WRITE(mvt->refillPushes, stream, depth + 2);
METER_WRITE(mvt->returns, stream); METER_WRITE(mvt->returns, stream, depth + 2);
METER_WRITE(mvt->perfectFits, stream); METER_WRITE(mvt->perfectFits, stream, depth + 2);
METER_WRITE(mvt->firstFits, stream); METER_WRITE(mvt->firstFits, stream, depth + 2);
METER_WRITE(mvt->secondFits, stream); METER_WRITE(mvt->secondFits, stream, depth + 2);
METER_WRITE(mvt->failures, stream); METER_WRITE(mvt->failures, stream, depth + 2);
METER_WRITE(mvt->emergencyContingencies, stream); METER_WRITE(mvt->emergencyContingencies, stream, depth + 2);
METER_WRITE(mvt->fragLimitContingencies, stream); METER_WRITE(mvt->fragLimitContingencies, stream, depth + 2);
METER_WRITE(mvt->contingencySearches, stream); METER_WRITE(mvt->contingencySearches, stream, depth + 2);
METER_WRITE(mvt->contingencyHardSearches, stream); METER_WRITE(mvt->contingencyHardSearches, stream, depth + 2);
METER_WRITE(mvt->splinters, stream); METER_WRITE(mvt->splinters, stream, depth + 2);
METER_WRITE(mvt->splintersUsed, stream); METER_WRITE(mvt->splintersUsed, stream, depth + 2);
METER_WRITE(mvt->splintersDropped, stream); METER_WRITE(mvt->splintersDropped, stream, depth + 2);
METER_WRITE(mvt->sawdust, stream); METER_WRITE(mvt->sawdust, stream, depth + 2);
METER_WRITE(mvt->exceptions, stream); METER_WRITE(mvt->exceptions, stream, depth + 2);
METER_WRITE(mvt->exceptionSplinters, stream); METER_WRITE(mvt->exceptionSplinters, stream, depth + 2);
METER_WRITE(mvt->exceptionReturns, stream); METER_WRITE(mvt->exceptionReturns, stream, depth + 2);
res = WriteF(stream, "}\n", NULL); res = WriteF(stream, depth, "} MVT $P\n", (WriteFP)mvt, NULL);
return res; return res;
} }
@ -1087,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 = 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 */ /* Internal methods */
@ -1137,7 +1132,7 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
/* Can't use plain old SegClass here because we need to call /* Can't use plain old SegClass here because we need to call
* SegBuffer() in MVTFree(). */ * SegBuffer() in MVTFree(). */
Res res = SegAlloc(segReturn, SegClassGet(), Res res = SegAlloc(segReturn, SegClassGet(),
SegPrefDefault(), size, MVT2Pool(mvt), withReservoirPermit, SegPrefDefault(), size, MVTPool(mvt), withReservoirPermit,
argsNone); argsNone);
if (res == ResOK) { if (res == ResOK) {
@ -1240,7 +1235,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size)
mvt->abqOverflow = FALSE; mvt->abqOverflow = FALSE;
METER_ACC(mvt->refills, size); METER_ACC(mvt->refills, size);
/* The iteration stops if the ABQ overflows, so may finish or not. */ /* The iteration stops if the ABQ overflows, so may finish or not. */
(void)LandIterate(MVTFailover(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE); (void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE);
} }
} }
@ -1306,12 +1301,12 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
MVTContigencyClosureStruct cls; MVTContigencyClosureStruct cls;
cls.mvt = mvt; cls.mvt = mvt;
cls.arena = PoolArena(MVT2Pool(mvt)); cls.arena = PoolArena(MVTPool(mvt));
cls.min = min; cls.min = min;
cls.steps = 0; cls.steps = 0;
cls.hardSteps = 0; cls.hardSteps = 0;
if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE)) if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE))
return FALSE; return FALSE;
AVER(RangeSize(&cls.range) >= min); AVER(RangeSize(&cls.range) >= min);
@ -1363,10 +1358,10 @@ Land _mps_mvt_cbs(Pool pool) {
MVT mvt; MVT mvt;
AVERT(Pool, pool); AVERT(Pool, pool);
mvt = Pool2MVT(pool); mvt = PoolMVT(pool);
AVERT(MVT, mvt); AVERT(MVT, mvt);
return MVTCBS(mvt); return MVTFreePrimary(mvt);
} }

View file

@ -6,24 +6,26 @@
* *
* .purpose: This is a pool class for manually managed objects of * .purpose: This is a pool class for manually managed objects of
* variable size where address-ordered first fit is an appropriate * variable size where address-ordered first fit is an appropriate
* policy. Provision is made to allocate in reverse. This pool * policy. Provision is made to allocate in reverse.
* can allocate across segment boundaries.
* *
* .design: <design/poolmvff> * .design: <design/poolmvff>
* *
* NOTE
* *
* TRANSGRESSIONS * There's potential for up to 4% speed improvement by calling Land
* * methods statically instead of indirectly via the Land abstraction
* .trans.stat: mps_mvff_stat is a temporary hack for measurement purposes, * (thus, cbsInsert instead of LandInsert, and so on). See
* see .stat below. * <https://info.ravenbrook.com/mail/2014/05/13/16-38-50/0/>
*/ */
#include "mpscmvff.h"
#include "dbgpool.h"
#include "cbs.h" #include "cbs.h"
#include "dbgpool.h"
#include "failover.h" #include "failover.h"
#include "freelist.h" #include "freelist.h"
#include "mpm.h" #include "mpm.h"
#include "mpscmvff.h"
#include "mpscmfs.h"
#include "poolmfs.h"
SRCID(poolmvff, "$Id$"); SRCID(poolmvff, "$Id$");
@ -43,25 +45,29 @@ extern PoolClass PoolClassMVFF(void);
typedef struct MVFFStruct *MVFF; typedef struct MVFFStruct *MVFF;
typedef struct MVFFStruct { /* MVFF pool outer structure */ typedef struct MVFFStruct { /* MVFF pool outer structure */
PoolStruct poolStruct; /* generic structure */ PoolStruct poolStruct; /* generic structure */
SegPref segPref; /* the preferences for segments */ SegPrefStruct segPrefStruct; /* the preferences for allocation */
Size extendBy; /* segment size to extend pool by */ Size extendBy; /* size to extend pool by */
Size minSegSize; /* minimum size of segment */
Size avgSize; /* client estimate of allocation size */ Size avgSize; /* client estimate of allocation size */
Size total; /* total bytes in pool */ double spare; /* spare space fraction, see MVFFReduce */
CBSStruct cbsStruct; /* free list */ MFSStruct cbsBlockPoolStruct; /* stores blocks for CBSs */
FreelistStruct flStruct; /* emergency free list */ CBSStruct totalCBSStruct; /* all memory allocated from the arena */
FailoverStruct foStruct; /* fail-over mechanism */ CBSStruct freeCBSStruct; /* free memory (primary) */
FreelistStruct flStruct; /* free memory (secondary, for emergencies) */
FailoverStruct foStruct; /* free memory (fail-over mechanism) */
Bool firstFit; /* as opposed to last fit */ Bool firstFit; /* as opposed to last fit */
Bool slotHigh; /* prefers high part of large block */ Bool slotHigh; /* prefers high part of large block */
Sig sig; /* <design/sig/> */ Sig sig; /* <design/sig/> */
} MVFFStruct; } MVFFStruct;
#define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool) #define PoolMVFF(pool) PARENT(MVFFStruct, poolStruct, pool)
#define MVFF2Pool(mvff) (&((mvff)->poolStruct)) #define MVFFPool(mvff) (&(mvff)->poolStruct)
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct)) #define MVFFTotalLand(mvff) CBSLand(&(mvff)->totalCBSStruct)
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct)) #define MVFFFreePrimary(mvff) CBSLand(&(mvff)->freeCBSStruct)
#define FailoverOfMVFF(mvff) (&((mvff)->foStruct.landStruct)) #define MVFFFreeSecondary(mvff) FreelistLand(&(mvff)->flStruct)
#define MVFFFreeLand(mvff) FailoverLand(&(mvff)->foStruct)
#define MVFFSegPref(mvff) (&(mvff)->segPrefStruct)
#define MVFFBlockPool(mvff) MFSPool(&(mvff)->cbsBlockPoolStruct)
static Bool MVFFCheck(MVFF mvff); static Bool MVFFCheck(MVFF mvff);
@ -80,176 +86,214 @@ typedef MVFFDebugStruct *MVFFDebug;
#define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct)) #define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct))
/* MVFFInsert -- add given range to free lists /* MVFFReduce -- return memory to the arena
* *
* Updates rangeIO to be maximally coalesced range containing given * This is usually called immediately after inserting a range into the
* range. Does not attempt to free segments (see MVFFFreeSegs). * MVFFFreeLand. (But not in all cases: see MVFFExtend.)
*/ */
static Res MVFFInsert(Range rangeIO, MVFF mvff) { static void MVFFReduce(MVFF mvff)
AVERT(Range, rangeIO);
AVERT(MVFF, mvff);
return LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO);
}
/* MVFFFreeSegs -- free segments from given range
*
* Given a free range, attempts to find entire segments within it, and
* returns them to the arena, updating total size counter.
*
* This is usually called immediately after MVFFInsert. It is not
* combined with MVFFInsert because the latter is also called when new
* segments are added under MVFFAlloc.
*/
static void MVFFFreeSegs(MVFF mvff, Range range)
{ {
Seg seg = NULL; /* suppress "may be used uninitialized" */
Arena arena; Arena arena;
Bool b; Size freeSize, freeLimit, targetFree;
Addr segLimit; /* limit of the current segment when iterating */ RangeStruct freeRange, oldFreeRange;
Addr segBase; /* base of the current segment when iterating */ Align grainSize;
Res res;
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVERT(Range, range); arena = PoolArena(MVFFPool(mvff));
/* Could profitably AVER that the given range is free, */
/* but the CBS doesn't provide that facility. */
if (RangeSize(range) < mvff->minSegSize) /* NOTE: Memory is returned to the arena in the smallest units
return; /* not large enough for entire segments */ possible (arena grains). There's a possibility that this could
lead to fragmentation in the arena (because allocation is in
multiples of mvff->extendBy). If so, try setting grainSize =
mvff->extendBy here. */
arena = PoolArena(MVFF2Pool(mvff)); grainSize = ArenaGrainSize(arena);
b = SegOfAddr(&seg, arena, RangeBase(range));
AVER(b);
segBase = SegBase(seg); /* Try to return memory when the amount of free memory exceeds a
segLimit = SegLimit(seg); threshold fraction of the total memory. */
while(segLimit <= RangeLimit(range)) { /* segment ends in range */ freeLimit = (Size)(LandSize(MVFFTotalLand(mvff)) * mvff->spare);
if (segBase >= RangeBase(range)) { /* segment starts in range */ freeSize = LandSize(MVFFFreeLand(mvff));
RangeStruct delRange, oldRange; if (freeSize < freeLimit)
RangeInit(&delRange, segBase, segLimit); return;
res = LandDelete(&oldRange, FailoverOfMVFF(mvff), &delRange); /* For hysteresis, return only a proportion of the free memory. */
AVER(res == ResOK);
AVER(RangesNest(&oldRange, &delRange));
/* Can't free the segment earlier, because if it was on the targetFree = freeLimit / 2;
* Freelist rather than the CBS then it likely contains data
* that needs to be read in order to update the Freelist. */
SegFree(seg);
AVER(mvff->total >= RangeSize(&delRange)); /* Each time around this loop we either break, or we free at least
mvff->total -= RangeSize(&delRange); one page back to the arena, thus ensuring that eventually the
} loop will terminate */
/* Avoid calling SegFindAboveAddr if the next segment would fail */ /* NOTE: If this code becomes very hot, then the test of whether there's
/* the loop test, mainly because there might not be a */ a large free block in the CBS could be inlined, since it's a property
/* next segment. */ stored at the root node. */
if (segLimit == RangeLimit(range)) /* segment ends at end of range */
while (freeSize > targetFree
&& LandFindLargest(&freeRange, &oldFreeRange, MVFFFreeLand(mvff),
grainSize, FindDeleteNONE))
{
RangeStruct pageRange, oldRange;
Size size;
Res res;
Addr base, limit;
AVER(RangesEqual(&freeRange, &oldFreeRange));
base = AddrAlignUp(RangeBase(&freeRange), grainSize);
limit = AddrAlignDown(RangeLimit(&freeRange), grainSize);
/* Give up if this block doesn't contain a whole aligned page,
even though smaller better-aligned blocks might, because
LandFindLargest won't be able to find those anyway. */
if (base >= limit)
break; break;
b = SegFindAboveAddr(&seg, arena, segBase); size = AddrOffset(base, limit);
AVER(b);
segBase = SegBase(seg); /* Don't return (much) more than we need to. */
segLimit = SegLimit(seg); if (size > freeSize - targetFree)
size = SizeAlignUp(freeSize - targetFree, grainSize);
/* Calculate the range of pages we can return to the arena near the
top end of the free memory (because we're first fit). */
RangeInit(&pageRange, AddrSub(limit, size), limit);
AVER(!RangeIsEmpty(&pageRange));
AVER(RangesNest(&freeRange, &pageRange));
AVER(RangeIsAligned(&pageRange, grainSize));
/* Delete the range from the free list before attempting to delete
it from the total allocated memory, so that we don't have
dangling blocks in the free list, even for a moment. If we fail
to delete from the TotalCBS we add back to the free list, which
can't fail. */
res = LandDelete(&oldRange, MVFFFreeLand(mvff), &pageRange);
if (res != ResOK)
break;
freeSize -= RangeSize(&pageRange);
AVER(freeSize == LandSize(MVFFFreeLand(mvff)));
res = LandDelete(&oldRange, MVFFTotalLand(mvff), &pageRange);
if (res != ResOK) {
RangeStruct coalescedRange;
res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &pageRange);
AVER(res == ResOK);
break;
} }
return; ArenaFree(RangeBase(&pageRange), RangeSize(&pageRange), MVFFPool(mvff));
}
} }
/* MVFFAddSeg -- Allocates a new segment from the arena /* MVFFExtend -- allocate a new range from the arena
* *
* Allocates a new segment from the arena (with the given * Allocate a new range from the arena (with the given
* withReservoirPermit flag) of at least the specified size. The * withReservoirPermit flag) of at least the specified size. The
* specified size should be pool-aligned. Adds it to the free lists. * specified size should be pool-aligned. Add it to the allocated and
* free lists.
*/ */
static Res MVFFAddSeg(Seg *segReturn, static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size,
MVFF mvff, Size size, Bool withReservoirPermit) Bool withReservoirPermit)
{ {
Pool pool; Pool pool;
Arena arena; Arena arena;
Size segSize; Size allocSize;
Seg seg; RangeStruct range, coalescedRange;
Addr base;
Res res; Res res;
RangeStruct range;
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVER(size > 0); AVER(size > 0);
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
pool = MVFF2Pool(mvff); pool = MVFFPool(mvff);
arena = PoolArena(pool); arena = PoolArena(pool);
AVER(SizeIsAligned(size, PoolAlignment(pool))); AVER(SizeIsAligned(size, PoolAlignment(pool)));
/* Use extendBy unless it's too small (see */ /* Use extendBy unless it's too small (see */
/* <design/poolmvff/#design.seg-size>). */ /* <design/poolmvff/#design.acquire-size>). */
if (size <= mvff->extendBy) if (size <= mvff->extendBy)
segSize = mvff->extendBy; allocSize = mvff->extendBy;
else else
segSize = size; allocSize = size;
segSize = SizeArenaGrains(segSize, arena); allocSize = SizeArenaGrains(allocSize, arena);
res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, res = ArenaAlloc(&base, MVFFSegPref(mvff), allocSize, pool,
withReservoirPermit, argsNone); withReservoirPermit);
if (res != ResOK) { if (res != ResOK) {
/* try again for a seg just large enough for object */ /* try again with a range just large enough for object */
/* see <design/poolmvff/#design.seg-fail> */ /* see <design/poolmvff/#design.seg-fail> */
segSize = SizeArenaGrains(size, arena); allocSize = SizeArenaGrains(size, arena);
res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, res = ArenaAlloc(&base, MVFFSegPref(mvff), allocSize, pool,
withReservoirPermit, argsNone); withReservoirPermit);
if (res != ResOK) { if (res != ResOK)
return res; return res;
} }
RangeInitSize(&range, base, allocSize);
res = LandInsert(&coalescedRange, MVFFTotalLand(mvff), &range);
if (res != ResOK) {
/* Can't record this memory, so return it to the arena and fail. */
ArenaFree(base, allocSize, pool);
return res;
} }
mvff->total += segSize;
RangeInitSize(&range, SegBase(seg), segSize);
DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range)); DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range));
res = MVFFInsert(&range, mvff); res = LandInsert(rangeReturn, MVFFFreeLand(mvff), &range);
/* Insertion must succeed because it fails over to a Freelist. */
AVER(res == ResOK); AVER(res == ResOK);
AVER(RangeBase(&range) <= SegBase(seg));
if (mvff->minSegSize > segSize) mvff->minSegSize = segSize;
/* Don't call MVFFFreeSegs; that would be silly. */ /* Don't call MVFFReduce; that would be silly. */
*segReturn = seg;
return ResOK; return ResOK;
} }
/* MVFFFindFree -- find the first (or last) suitable free block /* mvffFindFree -- find a suitable free block or add one
* *
* Finds a free block of the given (pool aligned) size, according * Finds a free block of the given (pool aligned) size, using the
* to a first (or last) fit policy controlled by the MVFF fields * policy (first fit, last fit, or worst fit) specified by findMethod
* firstFit, slotHigh (for whether to allocate the top or bottom * and findDelete.
* portion of a larger block).
* *
* Will return FALSE if the free lists have no large enough block. In * If there is no suitable free block, try extending the pool.
* particular, will not attempt to allocate a new segment.
*/ */
static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size) static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size,
LandFindMethod findMethod, FindDelete findDelete,
Bool withReservoirPermit)
{ {
Bool foundBlock; Bool found;
FindDelete findDelete;
RangeStruct oldRange; RangeStruct oldRange;
Land land;
AVER(rangeReturn != NULL); AVER(rangeReturn != NULL);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVER(size > 0); AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); AVER(SizeIsAligned(size, PoolAlignment(MVFFPool(mvff))));
AVER(FUNCHECK(findMethod));
AVERT(FindDelete, findDelete);
AVERT(Bool, withReservoirPermit);
findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; land = MVFFFreeLand(mvff);
found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete);
if (!found) {
RangeStruct newRange;
Res res;
res = MVFFExtend(&newRange, mvff, size, withReservoirPermit);
if (res != ResOK)
return res;
found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete);
foundBlock = /* We know that the found range must intersect the newly added
(mvff->firstFit ? LandFindFirst : LandFindLast) * range. But it doesn't necessarily lie entirely within it. */
(rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete); AVER(found && RangesOverlap(rangeReturn, &newRange));
}
AVER(found);
return foundBlock; return ResOK;
} }
@ -261,41 +305,27 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
Res res; Res res;
MVFF mvff; MVFF mvff;
RangeStruct range; RangeStruct range;
Bool foundBlock; LandFindMethod findMethod;
FindDelete findDelete;
AVERT(Pool, pool);
mvff = Pool2MVFF(pool);
AVERT(MVFF, mvff);
AVER(aReturn != NULL); AVER(aReturn != NULL);
AVERT(Pool, pool);
mvff = PoolMVFF(pool);
AVERT(MVFF, mvff);
AVER(size > 0); AVER(size > 0);
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
size = SizeAlignUp(size, PoolAlignment(pool)); size = SizeAlignUp(size, PoolAlignment(pool));
findMethod = mvff->firstFit ? LandFindFirst : LandFindLast;
findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW;
foundBlock = MVFFFindFree(&range, mvff, size); res = mvffFindFree(&range, mvff, size, findMethod, findDelete,
if (!foundBlock) { withReservoirPermit);
Seg seg;
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
if (res != ResOK) if (res != ResOK)
return res; return res;
foundBlock = MVFFFindFree(&range, mvff, size);
/* We know that the found range must intersect the new segment. */
/* In particular, it doesn't necessarily lie entirely within it. */
/* The next two AVERs test for intersection of two intervals. */
AVER(RangeBase(&range) < SegLimit(seg));
AVER(SegBase(seg) < RangeLimit(&range));
/* We also know that the found range is no larger than the segment. */
AVER(SegSize(seg) >= RangeSize(&range));
}
AVER(foundBlock);
AVER(RangeSize(&range) == size); AVER(RangeSize(&range) == size);
*aReturn = RangeBase(&range); *aReturn = RangeBase(&range);
return ResOK; return ResOK;
} }
@ -305,11 +335,11 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
static void MVFFFree(Pool pool, Addr old, Size size) static void MVFFFree(Pool pool, Addr old, Size size)
{ {
Res res; Res res;
RangeStruct range; RangeStruct range, coalescedRange;
MVFF mvff; MVFF mvff;
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVER(old != (Addr)0); AVER(old != (Addr)0);
@ -317,19 +347,17 @@ static void MVFFFree(Pool pool, Addr old, Size size)
AVER(size > 0); AVER(size > 0);
RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool))); RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool)));
res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &range);
res = MVFFInsert(&range, mvff); /* Insertion must succeed because it fails over to a Freelist. */
AVER(res == ResOK); AVER(res == ResOK);
if (res == ResOK) MVFFReduce(mvff);
MVFFFreeSegs(mvff, &range);
return;
} }
/* MVFFBufferFill -- Fill the buffer /* MVFFBufferFill -- Fill the buffer
* *
* Fill it with the largest block we can find. * Fill it with the largest block we can find. This is worst-fit
* allocation policy; see <design/poolmvff/#over.buffer>.
*/ */
static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn, static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size, Pool pool, Buffer buffer, Size size,
@ -337,29 +365,22 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
{ {
Res res; Res res;
MVFF mvff; MVFF mvff;
RangeStruct range, oldRange; RangeStruct range;
Bool found;
Seg seg = NULL;
AVER(baseReturn != NULL); AVER(baseReturn != NULL);
AVER(limitReturn != NULL); AVER(limitReturn != NULL);
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(size > 0); AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(pool))); AVER(SizeIsAligned(size, PoolAlignment(pool)));
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE); res = mvffFindFree(&range, mvff, size, LandFindLargest, FindDeleteENTIRE,
if (!found) { withReservoirPermit);
/* Add a new segment to the free lists and try again. */
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
if (res != ResOK) if (res != ResOK)
return res; return res;
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
}
AVER(found);
AVER(RangeSize(&range) >= size); AVER(RangeSize(&range) >= size);
*baseReturn = RangeBase(&range); *baseReturn = RangeBase(&range);
@ -375,10 +396,10 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer,
{ {
Res res; Res res;
MVFF mvff; MVFF mvff;
RangeStruct range; RangeStruct range, coalescedRange;
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
AVERT(Buffer, buffer); AVERT(Buffer, buffer);
AVER(BufferIsReady(buffer)); AVER(BufferIsReady(buffer));
@ -387,12 +408,9 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer,
if (RangeIsEmpty(&range)) if (RangeIsEmpty(&range))
return; return;
res = MVFFInsert(&range, mvff); res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &range);
AVER(res == ResOK); AVER(res == ResOK);
if (res == ResOK) MVFFReduce(mvff);
MVFFFreeSegs(mvff, &range);
return;
} }
@ -438,10 +456,10 @@ static Res MVFFInit(Pool pool, ArgList args)
Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT; Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT;
Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT; Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT;
Bool firstFit = MVFF_FIRST_FIT_DEFAULT; Bool firstFit = MVFF_FIRST_FIT_DEFAULT;
double spare = MVFF_SPARE_DEFAULT;
MVFF mvff; MVFF mvff;
Arena arena; Arena arena;
Res res; Res res;
void *p;
ArgStruct arg; ArgStruct arg;
AVERT(Pool, pool); AVERT(Pool, pool);
@ -461,6 +479,9 @@ static Res MVFFInit(Pool pool, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_ALIGN)) if (ArgPick(&arg, args, MPS_KEY_ALIGN))
align = arg.val.align; align = arg.val.align;
if (ArgPick(&arg, args, MPS_KEY_SPARE))
spare = arg.val.d;
if (ArgPick(&arg, args, MPS_KEY_MVFF_SLOT_HIGH)) if (ArgPick(&arg, args, MPS_KEY_MVFF_SLOT_HIGH))
slotHigh = arg.val.b; slotHigh = arg.val.b;
@ -473,6 +494,8 @@ static Res MVFFInit(Pool pool, ArgList args)
AVER(extendBy > 0); /* .arg.check */ AVER(extendBy > 0); /* .arg.check */
AVER(avgSize > 0); /* .arg.check */ AVER(avgSize > 0); /* .arg.check */
AVER(avgSize <= extendBy); /* .arg.check */ AVER(avgSize <= extendBy); /* .arg.check */
AVER(spare >= 0.0); /* .arg.check */
AVER(spare <= 1.0); /* .arg.check */
AVERT(Align, align); AVERT(Align, align);
/* This restriction on the alignment is necessary because of the use /* This restriction on the alignment is necessary because of the use
* of a Freelist to store the free address ranges in low-memory * of a Freelist to store the free address ranges in low-memory
@ -483,46 +506,60 @@ static Res MVFFInit(Pool pool, ArgList args)
AVERT(Bool, arenaHigh); AVERT(Bool, arenaHigh);
AVERT(Bool, firstFit); AVERT(Bool, firstFit);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
mvff->extendBy = extendBy; mvff->extendBy = extendBy;
if (extendBy < ArenaGrainSize(arena)) if (extendBy < ArenaGrainSize(arena))
mvff->minSegSize = ArenaGrainSize(arena); mvff->extendBy = ArenaGrainSize(arena);
else
mvff->minSegSize = extendBy;
mvff->avgSize = avgSize; mvff->avgSize = avgSize;
pool->alignment = align; pool->alignment = align;
mvff->slotHigh = slotHigh; mvff->slotHigh = slotHigh;
mvff->firstFit = firstFit; mvff->firstFit = firstFit;
mvff->spare = spare;
res = ControlAlloc(&p, arena, sizeof(SegPrefStruct), FALSE); SegPrefInit(MVFFSegPref(mvff));
SegPrefExpress(MVFFSegPref(mvff), arenaHigh ? SegPrefHigh : SegPrefLow, NULL);
/* An MFS pool is explicitly initialised for the two CBSs partly to
* share space, but mostly to avoid a call to PoolCreate, so that
* MVFF can be used during arena bootstrap as the control pool. */
MPS_ARGS_BEGIN(piArgs) {
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSFastBlockStruct));
res = PoolInit(MVFFBlockPool(mvff), arena, PoolClassMFS(), piArgs);
} MPS_ARGS_END(piArgs);
if (res != ResOK) if (res != ResOK)
return res; goto failBlockPoolInit;
mvff->segPref = (SegPref)p; MPS_ARGS_BEGIN(liArgs) {
SegPrefInit(mvff->segPref); MPS_ARGS_ADD(liArgs, CBSBlockPool, MVFFBlockPool(mvff));
SegPrefExpress(mvff->segPref, arenaHigh ? SegPrefHigh : SegPrefLow, NULL); res = LandInit(MVFFTotalLand(mvff), CBSFastLandClassGet(), arena, align,
mvff, liArgs);
} MPS_ARGS_END(liArgs);
if (res != ResOK)
goto failTotalLandInit;
mvff->total = 0; MPS_ARGS_BEGIN(liArgs) {
MPS_ARGS_ADD(liArgs, CBSBlockPool, MVFFBlockPool(mvff));
res = LandInit(MVFFFreePrimary(mvff), CBSFastLandClassGet(), arena, align,
mvff, liArgs);
} MPS_ARGS_END(liArgs);
if (res != ResOK)
goto failFreePrimaryInit;
res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, res = LandInit(MVFFFreeSecondary(mvff), FreelistLandClassGet(), arena, align,
mvff, mps_args_none); mvff, mps_args_none);
if (res != ResOK) if (res != ResOK)
goto failFreelistInit; goto failFreeSecondaryInit;
res = LandInit(CBSOfMVFF(mvff), CBSFastLandClassGet(), arena, align, mvff,
mps_args_none);
if (res != ResOK)
goto failCBSInit;
MPS_ARGS_BEGIN(foArgs) { MPS_ARGS_BEGIN(foArgs) {
MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff)); MPS_ARGS_ADD(foArgs, FailoverPrimary, MVFFFreePrimary(mvff));
MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff)); MPS_ARGS_ADD(foArgs, FailoverSecondary, MVFFFreeSecondary(mvff));
res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, res = LandInit(MVFFFreeLand(mvff), FailoverLandClassGet(), arena, align,
mvff, foArgs); mvff, foArgs);
} MPS_ARGS_END(foArgs); } MPS_ARGS_END(foArgs);
if (res != ResOK) if (res != ResOK)
goto failFailoverInit; goto failFreeLandInit;
mvff->sig = MVFFSig; mvff->sig = MVFFSig;
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
@ -530,50 +567,57 @@ static Res MVFFInit(Pool pool, ArgList args)
BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit)); BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit));
return ResOK; return ResOK;
failFailoverInit: failFreeLandInit:
LandFinish(CBSOfMVFF(mvff)); LandFinish(MVFFFreeSecondary(mvff));
failCBSInit: failFreeSecondaryInit:
LandFinish(FreelistOfMVFF(mvff)); LandFinish(MVFFFreePrimary(mvff));
failFreelistInit: failFreePrimaryInit:
ControlFree(arena, p, sizeof(SegPrefStruct)); LandFinish(MVFFTotalLand(mvff));
failTotalLandInit:
PoolFinish(MVFFBlockPool(mvff));
failBlockPoolInit:
return res; return res;
} }
/* MVFFFinish -- finish method for MVFF */ /* MVFFFinish -- finish method for MVFF */
static Bool mvffFinishVisitor(Land land, Range range,
void *closureP, Size closureS)
{
Pool pool;
AVERT(Land, land);
AVERT(Range, range);
AVER(closureP != NULL);
pool = closureP;
AVERT(Pool, pool);
UNUSED(closureS);
ArenaFree(RangeBase(range), RangeSize(range), pool);
return TRUE;
}
static void MVFFFinish(Pool pool) static void MVFFFinish(Pool pool)
{ {
MVFF mvff; MVFF mvff;
Arena arena;
Ring ring, node, nextNode;
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
ring = PoolSegRing(pool);
RING_FOR(node, ring, nextNode) {
Size size;
Seg seg;
seg = SegOfPoolRing(node);
AVER(SegPool(seg) == pool);
size = AddrOffset(SegBase(seg), SegLimit(seg));
AVER(size <= mvff->total);
mvff->total -= size;
SegFree(seg);
}
AVER(mvff->total == 0);
arena = PoolArena(pool);
ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct));
LandFinish(FailoverOfMVFF(mvff));
LandFinish(FreelistOfMVFF(mvff));
LandFinish(CBSOfMVFF(mvff));
mvff->sig = SigInvalid; mvff->sig = SigInvalid;
LandIterate(MVFFTotalLand(mvff), mvffFinishVisitor, pool, 0);
/* TODO: would like to check that LandSize(MVFFTotalLand(mvff)) == 0
* now, but CBS doesn't support deletion while iterating. See
* job003826. */
LandFinish(MVFFFreeLand(mvff));
LandFinish(MVFFFreeSecondary(mvff));
LandFinish(MVFFFreePrimary(mvff));
LandFinish(MVFFTotalLand(mvff));
PoolFinish(MVFFBlockPool(mvff));
} }
@ -584,46 +628,80 @@ static PoolDebugMixin MVFFDebugMixin(Pool pool)
MVFF mvff; MVFF mvff;
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
/* Can't check MVFFDebug, because this is called during init */ /* Can't check MVFFDebug, because this is called during init */
return &(MVFF2MVFFDebug(mvff)->debug); return &(MVFF2MVFFDebug(mvff)->debug);
} }
/* 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 */ /* MVFFDescribe -- describe an MVFF pool */
static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream) static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
MVFF mvff; MVFF mvff;
if (!TESTT(Pool, pool)) return ResFAIL; if (!TESTT(Pool, pool)) return ResFAIL;
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
if (!TESTT(MVFF, mvff)) return ResFAIL; if (!TESTT(MVFF, mvff)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"MVFF $P {\n", (WriteFP)mvff, "MVFF $P {\n", (WriteFP)mvff,
" pool $P ($U)\n", " pool $P ($U)\n",
(WriteFP)pool, (WriteFU)pool->serial, (WriteFP)pool, (WriteFU)pool->serial,
" extendBy $W\n", (WriteFW)mvff->extendBy, " extendBy $W\n", (WriteFW)mvff->extendBy,
" avgSize $W\n", (WriteFW)mvff->avgSize, " avgSize $W\n", (WriteFW)mvff->avgSize,
" total $U\n", (WriteFU)mvff->total, " firstFit $U\n", (WriteFU)mvff->firstFit,
" slotHigh $U\n", (WriteFU)mvff->slotHigh,
" spare $D\n", (WriteFD)mvff->spare,
NULL); NULL);
if (res != ResOK) if (res != ResOK) return res;
return res;
res = LandDescribe(CBSOfMVFF(mvff), stream); /* TODO: SegPrefDescribe(MVFFSegPref(mvff), stream); */
if (res != ResOK)
return res;
res = LandDescribe(FreelistOfMVFF(mvff), stream); /* Don't describe MVFFBlockPool(mvff) otherwise it'll appear twice
if (res != ResOK) * in the output of GlobalDescribe. */
return res;
res = WriteF(stream, "}\n", NULL); res = LandDescribe(MVFFTotalLand(mvff), stream, depth + 2);
if (res != ResOK) return res;
res = LandDescribe(MVFFFreePrimary(mvff), stream, depth + 2);
if (res != ResOK) return res;
res = LandDescribe(MVFFFreeSecondary(mvff), stream, depth + 2);
if (res != ResOK) return res;
res = WriteF(stream, depth, "} MVFF $P\n", (WriteFP)mvff, NULL);
return res; return res;
} }
@ -642,6 +720,8 @@ DEFINE_POOL_CLASS(MVFFPoolClass, this)
this->free = MVFFFree; this->free = MVFFFree;
this->bufferFill = MVFFBufferFill; this->bufferFill = MVFFBufferFill;
this->bufferEmpty = MVFFBufferEmpty; this->bufferEmpty = MVFFBufferEmpty;
this->totalSize = MVFFTotalSize;
this->freeSize = MVFFFreeSize;
this->describe = MVFFDescribe; this->describe = MVFFDescribe;
AVERT(PoolClass, this); AVERT(PoolClass, this);
} }
@ -681,57 +761,28 @@ mps_class_t mps_class_mvff_debug(void)
} }
/* Total free bytes. See <design/poolmvff/#design.arena-enter> */
size_t mps_mvff_free_size(mps_pool_t mps_pool)
{
Pool pool;
MVFF mvff;
Land land;
pool = (Pool)mps_pool;
AVERT(Pool, pool);
mvff = Pool2MVFF(pool);
AVERT(MVFF, mvff);
land = FailoverOfMVFF(mvff);
return (size_t)LandSize(land);
}
/* Total owned bytes. See <design/poolmvff/#design.arena-enter> */
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)mvff->total;
}
/* MVFFCheck -- check the consistency of an MVFF structure */ /* MVFFCheck -- check the consistency of an MVFF structure */
ATTRIBUTE_UNUSED ATTRIBUTE_UNUSED
static Bool MVFFCheck(MVFF mvff) static Bool MVFFCheck(MVFF mvff)
{ {
CHECKS(MVFF, mvff); CHECKS(MVFF, mvff);
CHECKD(Pool, MVFF2Pool(mvff)); CHECKD(Pool, MVFFPool(mvff));
CHECKL(IsSubclassPoly(MVFF2Pool(mvff)->class, MVFFPoolClassGet())); CHECKL(IsSubclassPoly(MVFFPool(mvff)->class, MVFFPoolClassGet()));
CHECKD(SegPref, mvff->segPref); CHECKD(SegPref, MVFFSegPref(mvff));
CHECKL(mvff->extendBy > 0); /* see .arg.check */ CHECKL(mvff->extendBy >= ArenaGrainSize(PoolArena(MVFFPool(mvff))));
CHECKL(mvff->minSegSize >= ArenaGrainSize(PoolArena(MVFF2Pool(mvff))));
CHECKL(mvff->avgSize > 0); /* see .arg.check */ CHECKL(mvff->avgSize > 0); /* see .arg.check */
CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */ CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */
CHECKL(SizeIsArenaGrains(mvff->total, PoolArena(MVFF2Pool(mvff)))); CHECKL(mvff->spare >= 0.0); /* see .arg.check */
CHECKD(CBS, &mvff->cbsStruct); CHECKL(mvff->spare <= 1.0); /* see .arg.check */
CHECKD(MFS, &mvff->cbsBlockPoolStruct);
CHECKD(CBS, &mvff->totalCBSStruct);
CHECKD(CBS, &mvff->freeCBSStruct);
CHECKD(Freelist, &mvff->flStruct); CHECKD(Freelist, &mvff->flStruct);
CHECKD(Failover, &mvff->foStruct); CHECKD(Failover, &mvff->foStruct);
CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff))); CHECKL(LandSize(MVFFTotalLand(mvff)) >= LandSize(MVFFFreeLand(mvff)));
CHECKL(SizeIsAligned(LandSize(MVFFFreeLand(mvff)), PoolAlignment(MVFFPool(mvff))));
CHECKL(SizeIsArenaGrains(LandSize(MVFFTotalLand(mvff)), PoolArena(MVFFPool(mvff))));
CHECKL(BoolCheck(mvff->slotHigh)); CHECKL(BoolCheck(mvff->slotHigh));
CHECKL(BoolCheck(mvff->firstFit)); CHECKL(BoolCheck(mvff->firstFit));
return TRUE; return TRUE;
@ -745,10 +796,10 @@ Land _mps_mvff_cbs(Pool pool) {
MVFF mvff; MVFF mvff;
AVERT(Pool, pool); AVERT(Pool, pool);
mvff = Pool2MVFF(pool); mvff = PoolMVFF(pool);
AVERT(MVFF, mvff); AVERT(MVFF, mvff);
return CBSOfMVFF(mvff); return MVFFFreePrimary(mvff);
} }

View file

@ -133,7 +133,7 @@ static void NBufferEmpty(Pool pool, Buffer buffer,
/* NDescribe -- describe method for class N */ /* NDescribe -- describe method for class N */
static Res NDescribe(Pool pool, mps_lib_FILE *stream) static Res NDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
{ {
PoolN poolN; PoolN poolN;
@ -142,6 +142,7 @@ static Res NDescribe(Pool pool, mps_lib_FILE *stream)
AVERT(PoolN, poolN); AVERT(PoolN, poolN);
UNUSED(stream); /* TODO: should output something here */ UNUSED(stream); /* TODO: should output something here */
UNUSED(depth);
return ResOK; return ResOK;
} }
@ -303,8 +304,8 @@ PoolClass PoolClassN(void)
Bool PoolNCheck(PoolN poolN) Bool PoolNCheck(PoolN poolN)
{ {
CHECKL(poolN != NULL); CHECKL(poolN != NULL);
CHECKD(Pool, &poolN->poolStruct); CHECKD(Pool, PoolNPool(poolN));
CHECKL(poolN->poolStruct.class == EnsureNPoolClass()); CHECKL(PoolNPool(poolN)->class == EnsureNPoolClass());
UNUSED(poolN); /* <code/mpm.c#check.unused> */ UNUSED(poolN); /* <code/mpm.c#check.unused> */
return TRUE; return TRUE;

View file

@ -5,10 +5,10 @@
*/ */
#include "mpm.h" #include "mpm.h"
#include "pooln.h"
#include "mpsavm.h" #include "mpsavm.h"
#include "testlib.h"
#include "mpslib.h" #include "mpslib.h"
#include "pooln.h"
#include "testlib.h"
#include <stdio.h> /* printf */ #include <stdio.h> /* printf */
@ -28,6 +28,7 @@ static void testit(ArenaClass class, ArgList args)
error("Error: Unexpectedly succeeded in" error("Error: Unexpectedly succeeded in"
"allocating block from PoolN\n"); "allocating block from PoolN\n");
} }
PoolDescribe(pool, mps_lib_get_stdout(), 0);
PoolDestroy(pool); PoolDestroy(pool);
ArenaDestroy(arena); ArenaDestroy(arena);
} }

View file

@ -24,9 +24,6 @@
SRCID(poolsnc, "$Id$"); SRCID(poolsnc, "$Id$");
#define SNCGen ((Serial)1) /* "generation" for SNC pools */
/* SNCStruct -- structure for an SNC pool /* SNCStruct -- structure for an SNC pool
* *
* See design.mps.poolsnc.poolstruct. * See design.mps.poolsnc.poolstruct.
@ -40,8 +37,8 @@ typedef struct SNCStruct {
Sig sig; Sig sig;
} SNCStruct, *SNC; } SNCStruct, *SNC;
#define Pool2SNC(pool) \ #define PoolSNC(pool) PARENT(SNCStruct, poolStruct, (pool))
PARENT(SNCStruct, poolStruct, (pool)) #define SNCPool(snc) (&(snc)->poolStruct)
/* Forward declarations */ /* Forward declarations */
@ -165,7 +162,7 @@ static void SNCBufFinish(Buffer buffer)
AVERT(SNCBuf, sncbuf); AVERT(SNCBuf, sncbuf);
pool = BufferPool(buffer); pool = BufferPool(buffer);
snc = Pool2SNC(pool); snc = PoolSNC(pool);
/* Put any segments which haven't bee popped onto the free list */ /* Put any segments which haven't bee popped onto the free list */
sncPopPartialSegChain(snc, buffer, NULL); sncPopPartialSegChain(snc, buffer, NULL);
@ -384,7 +381,7 @@ static Res SNCInit(Pool pool, ArgList args)
/* weak check, as half-way through initialization */ /* weak check, as half-way through initialization */
AVER(pool != NULL); AVER(pool != NULL);
snc = Pool2SNC(pool); snc = PoolSNC(pool);
ArgRequire(&arg, args, MPS_KEY_FORMAT); ArgRequire(&arg, args, MPS_KEY_FORMAT);
format = arg.val.format; format = arg.val.format;
@ -408,7 +405,7 @@ static void SNCFinish(Pool pool)
Ring ring, node, nextNode; Ring ring, node, nextNode;
AVERT(Pool, pool); AVERT(Pool, pool);
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
ring = &pool->segRing; ring = &pool->segRing;
@ -438,7 +435,7 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Bool, withReservoirPermit); AVERT(Bool, withReservoirPermit);
AVER(BufferIsReset(buffer)); AVER(BufferIsReset(buffer));
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
/* Try to find a free segment with enough space already */ /* Try to find a free segment with enough space already */
@ -485,7 +482,7 @@ static void SNCBufferEmpty(Pool pool, Buffer buffer,
seg = BufferSeg(buffer); seg = BufferSeg(buffer);
AVER(init <= limit); AVER(init <= limit);
AVER(SegLimit(seg) == limit); AVER(SegLimit(seg) == limit);
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
AVER(BufferFrameState(buffer) == BufferFrameVALID); AVER(BufferFrameState(buffer) == BufferFrameVALID);
/* .lw-frame-state */ /* .lw-frame-state */
@ -514,7 +511,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVERT(ScanState, ss); AVERT(ScanState, ss);
AVERT(Seg, seg); AVERT(Seg, seg);
AVERT(Pool, pool); AVERT(Pool, pool);
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
format = pool->format; format = pool->format;
@ -591,7 +588,7 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame)
AVERT(Pool, pool); AVERT(Pool, pool);
AVERT(Buffer, buf); AVERT(Buffer, buf);
/* frame is an Addr and can't be directly checked */ /* frame is an Addr and can't be directly checked */
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
AVER(BufferFrameState(buf) == BufferFrameVALID); AVER(BufferFrameState(buf) == BufferFrameVALID);
@ -644,7 +641,7 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
SNC snc; SNC snc;
Format format; Format format;
snc = Pool2SNC(pool); snc = PoolSNC(pool);
AVERT(SNC, snc); AVERT(SNC, snc);
format = pool->format; format = pool->format;
@ -702,8 +699,8 @@ ATTRIBUTE_UNUSED
static Bool SNCCheck(SNC snc) static Bool SNCCheck(SNC snc)
{ {
CHECKS(SNC, snc); CHECKS(SNC, snc);
CHECKD(Pool, &snc->poolStruct); CHECKD(Pool, SNCPool(snc));
CHECKL(snc->poolStruct.class == SNCPoolClassGet()); CHECKL(SNCPool(snc)->class == SNCPoolClassGet());
if (snc->freeSegs != NULL) { if (snc->freeSegs != NULL) {
CHECKD(Seg, snc->freeSegs); CHECKD(Seg, snc->freeSegs);
} }

View file

@ -41,19 +41,19 @@ void RangeFinish(Range range)
AVERT(Range, range); AVERT(Range, range);
} }
Res RangeDescribe(Range range, mps_lib_FILE *stream) Res RangeDescribe(Range range, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
AVERT(Range, range); AVERT(Range, range);
AVER(stream != NULL); AVER(stream != NULL);
res = WriteF(stream, res = WriteF(stream, depth,
"Range $P\n{\n", (WriteFP)range, "Range $P {\n", (WriteFP)range,
" base: $P\n", (WriteFP)RangeBase(range), " base: $P\n", (WriteFP)RangeBase(range),
" limit: $P\n", (WriteFP)RangeLimit(range), " limit: $P\n", (WriteFP)RangeLimit(range),
" size: $U\n", (WriteFU)RangeSize(range), " size: $U\n", (WriteFU)RangeSize(range),
"}\n", NULL); "} Range $P\n", (WriteFP)range, NULL);
if (res != ResOK) { if (res != ResOK) {
return res; return res;
} }

View file

@ -25,7 +25,7 @@
extern void RangeInit(Range range, Addr base, Addr limit); extern void RangeInit(Range range, Addr base, Addr limit);
extern void RangeInitSize(Range range, Addr base, Size size); extern void RangeInitSize(Range range, Addr base, Size size);
extern void RangeFinish(Range range); extern void RangeFinish(Range range);
extern Res RangeDescribe(Range range, mps_lib_FILE *stream); extern Res RangeDescribe(Range range, mps_lib_FILE *stream, Count depth);
extern Bool RangeCheck(Range range); extern Bool RangeCheck(Range range);
extern Bool RangeIsAligned(Range range, Align align); extern Bool RangeIsAligned(Range range, Align align);
extern Bool RangesOverlap(Range range1, Range range2); extern Bool RangesOverlap(Range range1, Range range2);

View file

@ -16,7 +16,7 @@ SRCID(reserv, "$Id$");
/* The reservoir pool is defined here. See <design/reservoir/> */ /* The reservoir pool is defined here. See <design/reservoir/> */
#define Pool2Reservoir(pool) PARENT(ReservoirStruct, poolStruct, pool) #define PoolReservoir(pool) PARENT(ReservoirStruct, poolStruct, pool)
/* Management of tracts /* Management of tracts
@ -30,7 +30,7 @@ SRCID(reserv, "$Id$");
#define resTractSetNext(tract, next) (TractSetP((tract), (void*)(next))) #define resTractSetNext(tract, next) (TractSetP((tract), (void*)(next)))
#define reservoirArena(reservoir) ((reservoir)->poolStruct.arena) #define reservoirArena(reservoir) (PoolArena(ReservoirPool(reservoir)))
/* ResPoolInit -- Reservoir pool init method */ /* ResPoolInit -- Reservoir pool init method */
@ -58,7 +58,7 @@ static void ResPoolFinish(Pool pool)
Reservoir reservoir; Reservoir reservoir;
AVERT(Pool, pool); AVERT(Pool, pool);
reservoir = Pool2Reservoir(pool); reservoir = PoolReservoir(pool);
AVERT(Reservoir, reservoir); AVERT(Reservoir, reservoir);
AVER(reservoir->reserve == NULL); /* .reservoir.finish */ AVER(reservoir->reserve == NULL); /* .reservoir.finish */
} }
@ -88,7 +88,7 @@ Bool ReservoirCheck(Reservoir reservoir)
CHECKS(Reservoir, reservoir); CHECKS(Reservoir, reservoir);
CHECKD(Pool, ReservoirPool(reservoir)); CHECKD(Pool, ReservoirPool(reservoir));
CHECKL(reservoir->poolStruct.class == reservoircl); CHECKL(ReservoirPool(reservoir)->class == reservoircl);
UNUSED(reservoircl); /* <code/mpm.c#check.unused> */ UNUSED(reservoircl); /* <code/mpm.c#check.unused> */
arena = reservoirArena(reservoir); arena = reservoirArena(reservoir);
CHECKU(Arena, arena); CHECKU(Arena, arena);

View file

@ -580,14 +580,14 @@ Res RootsIterate(Globals arena, RootIterateFn f, void *p)
/* RootDescribe -- describe a root */ /* RootDescribe -- describe a root */
Res RootDescribe(Root root, mps_lib_FILE *stream) Res RootDescribe(Root root, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
if (!TESTT(Root, root)) return ResFAIL; if (!TESTT(Root, root)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"Root $P ($U) {\n", (WriteFP)root, (WriteFU)root->serial, "Root $P ($U) {\n", (WriteFP)root, (WriteFU)root->serial,
" arena $P ($U)\n", (WriteFP)root->arena, " arena $P ($U)\n", (WriteFP)root->arena,
(WriteFU)root->arena->serial, (WriteFU)root->arena->serial,
@ -599,7 +599,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
switch(root->var) { switch(root->var) {
case RootTABLE: case RootTABLE:
res = WriteF(stream, res = WriteF(stream, depth + 2,
"table base $A limit $A\n", "table base $A limit $A\n",
root->the.table.base, root->the.table.limit, root->the.table.base, root->the.table.limit,
NULL); NULL);
@ -607,7 +607,8 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
break; break;
case RootTABLE_MASKED: case RootTABLE_MASKED:
res = WriteF(stream, " table base $A limit $A mask $B\n", res = WriteF(stream, depth + 2,
"table base $A limit $A mask $B\n",
root->the.tableMasked.base, root->the.tableMasked.limit, root->the.tableMasked.base, root->the.tableMasked.limit,
root->the.tableMasked.mask, root->the.tableMasked.mask,
NULL); NULL);
@ -615,7 +616,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
break; break;
case RootFUN: case RootFUN:
res = WriteF(stream, res = WriteF(stream, depth + 2,
"scan function $F\n", (WriteFF)root->the.fun.scan, "scan function $F\n", (WriteFF)root->the.fun.scan,
"environment p $P s $W\n", "environment p $P s $W\n",
root->the.fun.p, (WriteFW)root->the.fun.s, root->the.fun.p, (WriteFW)root->the.fun.s,
@ -624,7 +625,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
break; break;
case RootREG: case RootREG:
res = WriteF(stream, res = WriteF(stream, depth + 2,
"thread $P\n", (WriteFP)root->the.reg.thread, "thread $P\n", (WriteFP)root->the.reg.thread,
"environment p $P", root->the.reg.p, "environment p $P", root->the.reg.p,
NULL); NULL);
@ -632,7 +633,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
break; break;
case RootFMT: case RootFMT:
res = WriteF(stream, res = WriteF(stream, depth + 2,
"scan function $F\n", (WriteFF)root->the.fmt.scan, "scan function $F\n", (WriteFF)root->the.fmt.scan,
"format base $A limit $A\n", "format base $A limit $A\n",
root->the.fmt.base, root->the.fmt.limit, root->the.fmt.base, root->the.fmt.limit,
@ -644,7 +645,7 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
NOTREACHED; NOTREACHED;
} }
res = WriteF(stream, res = WriteF(stream, depth,
"} Root $P ($U)\n", (WriteFP)root, (WriteFU)root->serial, "} Root $P ($U)\n", (WriteFP)root, (WriteFU)root->serial,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
@ -655,14 +656,14 @@ Res RootDescribe(Root root, mps_lib_FILE *stream)
/* RootsDescribe -- describe all roots */ /* RootsDescribe -- describe all roots */
Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream) Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
{ {
Res res = ResOK; Res res = ResOK;
Ring node, next; Ring node, next;
RING_FOR(node, &arenaGlobals->rootRing, next) { RING_FOR(node, &arenaGlobals->rootRing, next) {
Root root = RING_ELT(Root, arenaRing, node); Root root = RING_ELT(Root, arenaRing, node);
res = RootDescribe(root, stream); /* this outputs too much */ res = RootDescribe(root, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
return res; return res;

View file

@ -357,7 +357,7 @@ void SegSetBuffer(Seg seg, Buffer buffer)
/* SegDescribe -- describe a segment */ /* SegDescribe -- describe a segment */
Res SegDescribe(Seg seg, mps_lib_FILE *stream) Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
Pool pool; Pool pool;
@ -367,7 +367,7 @@ Res SegDescribe(Seg seg, mps_lib_FILE *stream)
pool = SegPool(seg); pool = SegPool(seg);
res = WriteF(stream, res = WriteF(stream, depth,
"Segment $P [$A,$A) {\n", (WriteFP)seg, "Segment $P [$A,$A) {\n", (WriteFP)seg,
(WriteFA)SegBase(seg), (WriteFA)SegLimit(seg), (WriteFA)SegBase(seg), (WriteFA)SegLimit(seg),
" class $P (\"$S\")\n", " class $P (\"$S\")\n",
@ -377,11 +377,13 @@ Res SegDescribe(Seg seg, mps_lib_FILE *stream)
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = seg->class->describe(seg, stream); res = seg->class->describe(seg, stream, depth + 2);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, "\n", res = WriteF(stream, 0, "\n", NULL);
"} Segment $P\n", (WriteFP)seg, NULL); if (res != ResOK) return res;
res = WriteF(stream, depth, "} Segment $P\n", (WriteFP)seg, NULL);
return res; return res;
} }
@ -524,43 +526,6 @@ Bool SegNext(Seg *segReturn, Arena arena, Seg seg)
} }
/* SegFindAboveAddr -- return the "next" seg in the arena
*
* Finds the seg with the lowest base address which is
* greater than a specified address. The address must be (or once
* have been) the base address of a seg.
*/
Bool SegFindAboveAddr(Seg *segReturn, Arena arena, Addr addr)
{
Tract tract;
Addr base = addr;
AVER_CRITICAL(segReturn != NULL); /* .seg.critical */
AVERT_CRITICAL(Arena, arena);
while (TractNext(&tract, arena, base)) {
Seg seg;
if (TRACT_SEG(&seg, tract)) {
if (tract == seg->firstTract) {
*segReturn = seg;
return TRUE;
} else {
/* found the next tract in a large segment */
/* base & addr must be the base of this segment */
AVER_CRITICAL(TractBase(seg->firstTract) == addr);
AVER_CRITICAL(addr == base);
/* set base to the last tract in the segment */
base = AddrSub(seg->limit, ArenaGrainSize(arena));
AVER_CRITICAL(base > addr);
}
} else {
base = TractBase(tract);
}
}
return FALSE;
}
/* SegMerge -- Merge two adjacent segments /* SegMerge -- Merge two adjacent segments
* *
* See <design/seg/#merge> * See <design/seg/#merge>
@ -1026,56 +991,27 @@ static Res segTrivSplit(Seg seg, Seg segHi,
/* segTrivDescribe -- Basic Seg description method */ /* segTrivDescribe -- Basic Seg description method */
static Res segTrivDescribe(Seg seg, mps_lib_FILE *stream) static Res segTrivDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
if (!TESTT(Seg, seg)) return ResFAIL; if (!TESTT(Seg, seg)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
res = WriteF(stream, res = WriteF(stream, depth,
"shield depth $U\n", (WriteFU)seg->depth, "shield depth $U\n", (WriteFU)seg->depth,
"protection mode: ", "protection mode: ",
NULL); (SegPM(seg) & AccessREAD) ? "" : "!", "READ", " ",
if (res != ResOK) return res; (SegPM(seg) & AccessWRITE) ? "" : "!", "WRITE", "\n",
if (SegPM(seg) & AccessREAD) { "shield mode: ",
res = WriteF(stream, " read", NULL); (SegSM(seg) & AccessREAD) ? "" : "!", "READ", " ",
if (res != ResOK) return res; (SegSM(seg) & AccessWRITE) ? "" : "!", "WRITE", "\n",
} "ranks:",
if (SegPM(seg) & AccessWRITE) { RankSetIsMember(seg->rankSet, RankAMBIG) ? " ambiguous" : "",
res = WriteF(stream, " write", NULL); RankSetIsMember(seg->rankSet, RankEXACT) ? " exact" : "",
if (res != ResOK) return res; RankSetIsMember(seg->rankSet, RankFINAL) ? " final" : "",
} RankSetIsMember(seg->rankSet, RankWEAK) ? " weak" : "",
res = WriteF(stream, "\n shield mode:", NULL); "\n",
if (res != ResOK) return res;
if (SegSM(seg) & AccessREAD) {
res = WriteF(stream, " read", NULL);
if (res != ResOK) return res;
}
if (SegSM(seg) & AccessWRITE) {
res = WriteF(stream, " write", NULL);
if (res != ResOK) return res;
}
res = WriteF(stream, "\n ranks:", NULL);
if (res != ResOK) return res;
/* This bit ought to be in a RankSetDescribe in ref.c. */
if (RankSetIsMember(seg->rankSet, RankAMBIG)) {
res = WriteF(stream, " ambiguous", NULL);
if (res != ResOK) return res;
}
if (RankSetIsMember(seg->rankSet, RankEXACT)) {
res = WriteF(stream, " exact", NULL);
if (res != ResOK) return res;
}
if (RankSetIsMember(seg->rankSet, RankFINAL)) {
res = WriteF(stream, " final", NULL);
if (res != ResOK) return res;
}
if (RankSetIsMember(seg->rankSet, RankWEAK)) {
res = WriteF(stream, " weak", NULL);
if (res != ResOK) return res;
}
res = WriteF(stream, "\n",
"white $B\n", (WriteFB)seg->white, "white $B\n", (WriteFB)seg->white,
"grey $B\n", (WriteFB)seg->grey, "grey $B\n", (WriteFB)seg->grey,
"nailed $B\n", (WriteFB)seg->nailed, "nailed $B\n", (WriteFB)seg->nailed,
@ -1612,7 +1548,7 @@ failSuper:
/* gcSegDescribe -- GCSeg description method */ /* gcSegDescribe -- GCSeg description method */
static Res gcSegDescribe(Seg seg, mps_lib_FILE *stream) static Res gcSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
SegClass super; SegClass super;
@ -1625,19 +1561,18 @@ static Res gcSegDescribe(Seg seg, mps_lib_FILE *stream)
/* Describe the superclass fields first via next-method call */ /* Describe the superclass fields first via next-method call */
super = SEG_SUPERCLASS(GCSegClass); super = SEG_SUPERCLASS(GCSegClass);
res = super->describe(seg, stream); res = super->describe(seg, stream, depth);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, res = WriteF(stream, depth,
"summary $W\n", (WriteFW)gcseg->summary, "summary $W\n", (WriteFW)gcseg->summary,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (gcseg->buffer == NULL) { if (gcseg->buffer == NULL) {
res = WriteF(stream, " buffer: NULL\n", NULL); res = WriteF(stream, depth, "buffer: NULL\n", NULL);
} } else {
else { res = BufferDescribe(gcseg->buffer, stream, depth);
res = BufferDescribe(gcseg->buffer, stream);
} }
if (res != ResOK) return res; if (res != ResOK) return res;

View file

@ -52,7 +52,7 @@ typedef struct AMSTStruct {
typedef struct AMSTStruct *AMST; typedef struct AMSTStruct *AMST;
#define Pool2AMST(pool) PARENT(AMSTStruct, amsStruct, PARENT(AMSStruct, poolStruct, (pool))) #define PoolAMST(pool) PARENT(AMSTStruct, amsStruct, PARENT(AMSStruct, poolStruct, (pool)))
#define AMST2AMS(amst) (&(amst)->amsStruct) #define AMST2AMS(amst) (&(amst)->amsStruct)
@ -122,7 +122,7 @@ static Res amstSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Seg, seg); AVERT(Seg, seg);
amstseg = Seg2AMSTSeg(seg); amstseg = Seg2AMSTSeg(seg);
AVERT(Pool, pool); AVERT(Pool, pool);
amst = Pool2AMST(pool); amst = PoolAMST(pool);
AVERT(AMST, amst); AVERT(AMST, amst);
/* no useful checks for base and size */ /* no useful checks for base and size */
AVERT(Bool, reservoirPermit); AVERT(Bool, reservoirPermit);
@ -190,7 +190,7 @@ static Res amstSegMerge(Seg seg, Seg segHi,
amstsegHi = Seg2AMSTSeg(segHi); amstsegHi = Seg2AMSTSeg(segHi);
AVERT(AMSTSeg, amstseg); AVERT(AMSTSeg, amstseg);
AVERT(AMSTSeg, amstsegHi); AVERT(AMSTSeg, amstsegHi);
amst = Pool2AMST(SegPool(seg)); amst = PoolAMST(SegPool(seg));
/* Merge the superclass fields via direct next-method call */ /* Merge the superclass fields via direct next-method call */
super = SEG_SUPERCLASS(AMSTSegClass); super = SEG_SUPERCLASS(AMSTSegClass);
@ -241,7 +241,7 @@ static Res amstSegSplit(Seg seg, Seg segHi,
amstseg = Seg2AMSTSeg(seg); amstseg = Seg2AMSTSeg(seg);
amstsegHi = Seg2AMSTSeg(segHi); amstsegHi = Seg2AMSTSeg(segHi);
AVERT(AMSTSeg, amstseg); AVERT(AMSTSeg, amstseg);
amst = Pool2AMST(SegPool(seg)); amst = PoolAMST(SegPool(seg));
/* Split the superclass fields via direct next-method call */ /* Split the superclass fields via direct next-method call */
super = SEG_SUPERCLASS(AMSTSegClass); super = SEG_SUPERCLASS(AMSTSegClass);
@ -351,11 +351,11 @@ static Res AMSTInit(Pool pool, ArgList args)
ArgRequire(&arg, args, MPS_KEY_FORMAT); ArgRequire(&arg, args, MPS_KEY_FORMAT);
format = arg.val.format; format = arg.val.format;
res = AMSInitInternal(Pool2AMS(pool), format, chain, gen, FALSE); res = AMSInitInternal(PoolAMS(pool), format, chain, gen, FALSE);
if (res != ResOK) if (res != ResOK)
return res; return res;
amst = Pool2AMST(pool); amst = PoolAMST(pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
ams->segSize = AMSTSegSizePolicy; ams->segSize = AMSTSegSizePolicy;
ams->segClass = AMSTSegClassGet; ams->segClass = AMSTSegClassGet;
amst->failSegs = TRUE; amst->failSegs = TRUE;
@ -378,7 +378,7 @@ static void AMSTFinish(Pool pool)
AMST amst; AMST amst;
AVERT(Pool, pool); AVERT(Pool, pool);
amst = Pool2AMST(pool); amst = PoolAMST(pool);
AVERT(AMST, amst); AVERT(AMST, amst);
printf("\nDestroying pool, having performed:\n"); printf("\nDestroying pool, having performed:\n");
@ -418,7 +418,7 @@ static Bool AMSSegRegionIsFree(Seg seg, Addr base, Addr limit)
AVERT(Seg, seg); AVERT(Seg, seg);
amsseg = Seg2AMSSeg(seg); amsseg = Seg2AMSSeg(seg);
sbase = SegBase(seg); sbase = SegBase(seg);
ams = Pool2AMS(SegPool(seg)); ams = PoolAMS(SegPool(seg));
bgrain = AMSGrains(ams, AddrOffset(sbase, base)); bgrain = AMSGrains(ams, AddrOffset(sbase, base));
lgrain = AMSGrains(ams, AddrOffset(sbase, limit)); lgrain = AMSGrains(ams, AddrOffset(sbase, limit));
@ -544,8 +544,8 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(limitReturn != NULL); AVER(limitReturn != NULL);
/* other parameters are checked by next method */ /* other parameters are checked by next method */
arena = PoolArena(pool); arena = PoolArena(pool);
ams = Pool2AMS(pool); ams = PoolAMS(pool);
amst = Pool2AMST(pool); amst = PoolAMST(pool);
/* call next method */ /* call next method */
super = POOL_SUPERCLASS(AMSTPoolClass); super = POOL_SUPERCLASS(AMSTPoolClass);
@ -630,7 +630,7 @@ static void AMSTStressBufferedSeg(Seg seg, Buffer buffer)
AVERT(AMSTSeg, amstseg); AVERT(AMSTSeg, amstseg);
limit = BufferLimit(buffer); limit = BufferLimit(buffer);
arena = PoolArena(SegPool(seg)); arena = PoolArena(SegPool(seg));
amst = Pool2AMST(SegPool(seg)); amst = PoolAMST(SegPool(seg));
AVERT(AMST, amst); AVERT(AMST, amst);
if (amstseg->next != NULL) { if (amstseg->next != NULL) {

View file

@ -164,6 +164,21 @@ void SplayDebugUpdate(SplayTree splay, Tree tree)
} }
/* SplayDebugCount -- count and check order of tree
*
* This function may be called from a debugger or temporarily inserted
* during development to check a tree's integrity. It may not be called
* from the production MPS because it uses indefinite stack depth.
* See <code/tree.c#.note.stack>.
*/
Count SplayDebugCount(SplayTree splay)
{
AVERT(SplayTree, splay);
return TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey);
}
/* SplayZig -- move to left child, prepending to right tree /* SplayZig -- move to left child, prepending to right tree
* *
* Link the top node of the middle tree into the left child of the * Link the top node of the middle tree into the left child of the
@ -679,7 +694,7 @@ static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare)
SplayStateStruct stateStruct; SplayStateStruct stateStruct;
#ifdef SPLAY_DEBUG #ifdef SPLAY_DEBUG
Count count = TreeDebugCount(SplayTreeRoot(tree), tree->compare, tree->nodeKey); Count count = SplayDebugCount(splay);
#endif #endif
/* Short-circuit common cases. Splay trees often bring recently /* Short-circuit common cases. Splay trees often bring recently
@ -699,7 +714,7 @@ static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare)
SplayTreeSetRoot(splay, stateStruct.middle); SplayTreeSetRoot(splay, stateStruct.middle);
#ifdef SPLAY_DEBUG #ifdef SPLAY_DEBUG
AVER(count == TreeDebugCount(SplayTreeRoot(tree), tree->compare, tree->nodeKey)); AVER(count == SplayDebugCount(splay));
#endif #endif
return cmp; return cmp;
@ -894,7 +909,7 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
Bool found; Bool found;
Compare cmp; Compare cmp;
#ifdef SPLAY_DEBUG #ifdef SPLAY_DEBUG
Count count = TreeDebugCount(SplayTreeRoot(tree), tree->compare, tree->nodeKey); Count count = SplayDebugCount(splay);
#endif #endif
@ -936,7 +951,7 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
SplayTreeSetRoot(splay, stateStruct.middle); SplayTreeSetRoot(splay, stateStruct.middle);
#ifdef SPLAY_DEBUG #ifdef SPLAY_DEBUG
AVER(count == TreeDebugCount(SplayTreeRoot(tree), tree->compare, tree->nodeKey)); AVER(count == SplayDebugCount(splay));
#endif #endif
return found; return found;
@ -988,10 +1003,10 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
default: default:
NOTREACHED; NOTREACHED;
/* defensive fall-through */ /* defensive fall-through */
case CompareGREATER: case CompareLESS:
return SplayTreeRoot(splay); return SplayTreeRoot(splay);
case CompareLESS: case CompareGREATER:
case CompareEQUAL: case CompareEQUAL:
return SplayTreeSuccessor(splay); return SplayTreeSuccessor(splay);
} }
@ -1005,22 +1020,22 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
*/ */
static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream, static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
TreeDescribeMethod nodeDescribe) { TreeDescribeMethod nodeDescribe)
{
Res res; Res res;
#if defined(AVER_AND_CHECK)
if (!TreeCheck(node)) return ResFAIL; if (!TreeCheck(node)) return ResFAIL;
/* stream and nodeDescribe checked by SplayTreeDescribe */ if (stream == NULL) return ResFAIL;
#endif if (!FUNCHECK(nodeDescribe)) return ResFAIL;
res = WriteF(stream, "( ", NULL); res = WriteF(stream, 0, "( ", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (TreeHasLeft(node)) { if (TreeHasLeft(node)) {
res = SplayNodeDescribe(TreeLeft(node), stream, nodeDescribe); res = SplayNodeDescribe(TreeLeft(node), stream, nodeDescribe);
if (res != ResOK) return res; if (res != ResOK) return res;
res = WriteF(stream, " / ", NULL); res = WriteF(stream, 0, " / ", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
@ -1028,14 +1043,14 @@ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
if (res != ResOK) return res; if (res != ResOK) return res;
if (TreeHasRight(node)) { if (TreeHasRight(node)) {
res = WriteF(stream, " \\ ", NULL); res = WriteF(stream, 0, " \\ ", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
res = SplayNodeDescribe(TreeRight(node), stream, nodeDescribe); res = SplayNodeDescribe(TreeRight(node), stream, nodeDescribe);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, " )", NULL); res = WriteF(stream, 0, " )", NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
return ResOK; return ResOK;
@ -1336,28 +1351,31 @@ void SplayNodeInit(SplayTree splay, Tree node)
* See <design/splay/#function.splay.tree.describe>. * See <design/splay/#function.splay.tree.describe>.
*/ */
Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth,
TreeDescribeMethod nodeDescribe) { TreeDescribeMethod nodeDescribe)
{
Res res; Res res;
#if defined(AVER_AND_CHECK) if (!TESTT(SplayTree, splay)) return ResFAIL;
if (!SplayTreeCheck(splay)) return ResFAIL;
if (stream == NULL) return ResFAIL; if (stream == NULL) return ResFAIL;
if (!FUNCHECK(nodeDescribe)) return ResFAIL; if (!FUNCHECK(nodeDescribe)) return ResFAIL;
#endif
res = WriteF(stream, res = WriteF(stream, depth,
"Splay $P {\n", (WriteFP)splay, "Splay $P {\n", (WriteFP)splay,
" compare $F\n", (WriteFF)splay->compare, " compare $F\n", (WriteFF)splay->compare,
" nodeKey $F\n", (WriteFF)splay->nodeKey,
" updateNode $F\n", (WriteFF)splay->updateNode,
NULL); NULL);
if (res != ResOK) return res; if (res != ResOK) return res;
if (SplayTreeRoot(splay) != TreeEMPTY) { if (SplayTreeRoot(splay) != TreeEMPTY) {
res = WriteF(stream, depth, " tree ", NULL);
if (res != ResOK) return res;
res = SplayNodeDescribe(SplayTreeRoot(splay), stream, nodeDescribe); res = SplayNodeDescribe(SplayTreeRoot(splay), stream, nodeDescribe);
if (res != ResOK) return res; if (res != ResOK) return res;
} }
res = WriteF(stream, "\n}\n", NULL); res = WriteF(stream, depth, "\n} Splay $P\n", (WriteFP)splay, NULL);
return res; return res;
} }

View file

@ -72,9 +72,10 @@ extern void SplayNodeRefresh(SplayTree splay, Tree node);
extern void SplayNodeInit(SplayTree splay, Tree node); extern void SplayNodeInit(SplayTree splay, Tree node);
extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
TreeDescribeMethod nodeDescribe); Count depth, TreeDescribeMethod nodeDescribe);
extern void SplayDebugUpdate(SplayTree splay, Tree tree); extern void SplayDebugUpdate(SplayTree splay, Tree tree);
extern Count SplayDebugCount(SplayTree splay);
#endif /* splay_h */ #endif /* splay_h */

View file

@ -28,7 +28,7 @@ extern Bool ThreadCheck(Thread thread);
extern Bool ThreadCheckSimple(Thread thread); extern Bool ThreadCheckSimple(Thread thread);
extern Res ThreadDescribe(Thread thread, mps_lib_FILE *stream); extern Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth);
/* Register/Deregister /* Register/Deregister

View file

@ -128,11 +128,11 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
} }
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream) Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
res = WriteF(stream, res = WriteF(stream, depth,
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n", " arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial, (WriteFP)thread->arena, (WriteFU)thread->arena->serial,

View file

@ -272,11 +272,11 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
/* ThreadDescribe -- describe a thread */ /* ThreadDescribe -- describe a thread */
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream) Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
res = WriteF(stream, res = WriteF(stream, depth,
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n", " arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial, (WriteFP)thread->arena, (WriteFU)thread->arena->serial,

View file

@ -212,11 +212,11 @@ Arena ThreadArena(Thread thread)
return thread->arena; return thread->arena;
} }
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream) Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
res = WriteF(stream, res = WriteF(stream, depth,
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n", " arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial, (WriteFP)thread->arena, (WriteFU)thread->arena->serial,

View file

@ -248,11 +248,11 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
} }
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream) Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
{ {
Res res; Res res;
res = WriteF(stream, res = WriteF(stream, depth,
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
" arena $P ($U)\n", " arena $P ($U)\n",
(WriteFP)thread->arena, (WriteFU)thread->arena->serial, (WriteFP)thread->arena, (WriteFU)thread->arena->serial,

View file

@ -1260,7 +1260,12 @@ mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
{ {
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss); ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
Ref ref; Ref ref;
Chunk chunk;
Index i;
Tract tract; Tract tract;
Seg seg;
Res res;
Pool pool;
/* Special AVER macros are used on the critical path. */ /* Special AVER macros are used on the critical path. */
/* See <design/trace/#fix.noaver> */ /* See <design/trace/#fix.noaver> */
@ -1277,13 +1282,49 @@ mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
STATISTIC(++ss->fixRefCount); STATISTIC(++ss->fixRefCount);
EVENT4(TraceFix, ss, mps_ref_io, ref, ss->rank); EVENT4(TraceFix, ss, mps_ref_io, ref, ss->rank);
TRACT_OF_ADDR(&tract, ss->arena, ref); /* This sequence of tests is equivalent to calling TractOfAddr(),
if(tract) { * but inlined so that we can distinguish between "not pointing to
if(TraceSetInter(TractWhite(tract), ss->traces) != TraceSetEMPTY) { * chunk" and "pointing to chunk but not to tract" so that we can
Seg seg; * check the rank in the latter case. See
* <design/trace/#fix.tractofaddr.inline>
*
* If compilers fail to do a good job of inlining ChunkOfAddr and
* TreeFind then it may become necessary to inline at least the
* comparison against the root of the tree. See
* <https://info.ravenbrook.com/mail/2014/06/11/13-32-08/0/>
*/
if (!ChunkOfAddr(&chunk, ss->arena, ref))
/* Reference points outside MPS-managed address space: ignore. */
goto done;
i = INDEX_OF_ADDR(chunk, ref);
if (!BTGet(chunk->allocTable, i)) {
/* Reference points into a chunk but not to an allocated tract.
* See <design/trace/#exact.legal> */
AVER_CRITICAL(ss->rank < RankEXACT);
goto done;
}
tract = PageTract(&chunk->pageTable[i]);
if (TraceSetInter(TractWhite(tract), ss->traces) == TraceSetEMPTY) {
/* Reference points to a tract that is not white for any of the
* active traces. See <design/trace/#fix.tractofaddr> */
STATISTIC_STAT
({
if(TRACT_SEG(&seg, tract)) { if(TRACT_SEG(&seg, tract)) {
Res res; ++ss->segRefCount;
Pool pool; EVENT1(TraceFixSeg, seg);
}
});
goto done;
}
if (!TRACT_SEG(&seg, tract)) {
/* Tracts without segments must not be condemned. */
NOTREACHED;
goto done;
}
STATISTIC(++ss->segRefCount); STATISTIC(++ss->segRefCount);
STATISTIC(++ss->whiteSegRefCount); STATISTIC(++ss->whiteSegRefCount);
EVENT1(TraceFixSeg, seg); EVENT1(TraceFixSeg, seg);
@ -1291,7 +1332,7 @@ mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
pool = TractPool(tract); pool = TractPool(tract);
res = (*ss->fix)(pool, ss, seg, &ref); res = (*ss->fix)(pool, ss, seg, &ref);
if (res != ResOK) { if (res != ResOK) {
/* PoolFixEmergency should never fail. */ /* PoolFixEmergency must not fail. */
AVER_CRITICAL(ss->fix != PoolFixEmergency); AVER_CRITICAL(ss->fix != PoolFixEmergency);
/* Fix protocol (de facto): if Fix fails, ref must be unchanged /* Fix protocol (de facto): if Fix fails, ref must be unchanged
* Justification for this restriction: * Justification for this restriction:
@ -1300,36 +1341,11 @@ mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io)
* C: the code (here) already assumes this: it returns without * C: the code (here) already assumes this: it returns without
* updating ss->fixedSummary. RHSK 2007-03-21. * updating ss->fixedSummary. RHSK 2007-03-21.
*/ */
AVER(ref == (Ref)*mps_ref_io); AVER_CRITICAL(ref == (Ref)*mps_ref_io);
return res; return res;
} }
} else {
/* Only tracts with segments ought to have been condemned. */
/* SegOfAddr FALSE => a ref into a non-seg Tract (poolmv etc) */
/* .notwhite: ...But it should NOT be white.
* [I assert this both from logic, and from inspection of the
* current condemn code. RHSK 2010-11-30]
*/
NOTREACHED;
}
} else {
/* Tract isn't white. Don't compute seg for non-statistical */
/* variety. See <design/trace/#fix.tractofaddr> */
STATISTIC_STAT
({
Seg seg;
if(TRACT_SEG(&seg, tract)) {
++ss->segRefCount;
EVENT1(TraceFixSeg, seg);
}
});
}
} else {
/* See <design/trace/#exact.legal> */
AVER(ss->rank < RankEXACT
|| !ArenaIsReservedAddr(ss->arena, ref));
}
done:
/* See <design/trace/#fix.fixed.all> */ /* See <design/trace/#fix.fixed.all> */
ss->fixedSummary = RefSetAdd(ss->arena, ss->fixedSummary, ref); ss->fixedSummary = RefSetAdd(ss->arena, ss->fixedSummary, ref);
@ -1893,6 +1909,51 @@ failStart:
} }
/* TraceDescribe -- describe a trace */
Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth)
{
Res res;
const char *state;
if (!TESTT(Trace, trace)) return ResFAIL;
if (stream == NULL) return ResFAIL;
switch (trace->state) {
case TraceINIT: state = "INIT"; break;
case TraceUNFLIPPED: state = "UNFLIPPED"; break;
case TraceFLIPPED: state = "FLIPPED"; break;
case TraceRECLAIM: state = "RECLAIM"; break;
case TraceFINISHED: state = "FINISHED"; break;
default: state = "unknown"; break;
}
res = WriteF(stream, depth,
"Trace $P ($U) {\n", (WriteFP)trace, (WriteFU)trace->ti,
" arena $P ($U)\n", (WriteFP)trace->arena,
(WriteFU)trace->arena->serial,
" why \"$S\"\n", (WriteFS)TraceStartWhyToString(trace->why),
" state $S\n", (WriteFS)state,
" band $U\n", (WriteFU)trace->band,
" white $B\n", (WriteFB)trace->white,
" mayMove $B\n", (WriteFB)trace->mayMove,
" chain $P\n", (WriteFP)trace->chain,
" condemned $U\n", (WriteFU)trace->condemned,
" notCondemned $U\n", (WriteFU)trace->notCondemned,
" foundation $U\n", (WriteFU)trace->foundation,
" rate $U\n", (WriteFU)trace->rate,
" rootScanSize $U\n", (WriteFU)trace->rootScanSize,
" rootCopiedSize $U\n", (WriteFU)trace->rootCopiedSize,
" segScanSize $U\n", (WriteFU)trace->segScanSize,
" segCopiedSize $U\n", (WriteFU)trace->segCopiedSize,
" forwardedSize $U\n", (WriteFU)trace->forwardedSize,
" preservedInPlaceSize $U\n", (WriteFU)trace->preservedInPlaceSize,
"} Trace $P\n", (WriteFP)trace,
NULL);
return res;
}
/* C. COPYRIGHT AND LICENSE /* C. COPYRIGHT AND LICENSE
* *
* Copyright (C) 2001-2014 Ravenbrook Limited * Copyright (C) 2001-2014 Ravenbrook Limited

View file

@ -7,6 +7,17 @@
* free but never allocated as alloc starts searching after the tables. * free but never allocated as alloc starts searching after the tables.
* TractOfAddr uses the fact that these pages are marked as free in order * TractOfAddr uses the fact that these pages are marked as free in order
* to detect "references" to these pages as being bogus. * to detect "references" to these pages as being bogus.
*
* .chunk.at.base: The chunks are stored in a balanced binary tree.
* Looking up an address in this tree is on the critical path, and
* therefore vital that it runs quickly. It is an implementation
* detail of chunks that they are always stored at the base of the
* region of address space they represent. Thus chunk happens to
* always be the same as chunk->base. We take advantage of this in the
* tree search by using chunk as its own key (instead of looking up
* chunk->base): this saves a dereference and perhaps a cache miss.
* See ChunkKey and ChunkCompare for this optimization. The necessary
* property is asserted in ChunkCheck.
*/ */
#include "tract.h" #include "tract.h"
@ -17,9 +28,6 @@
SRCID(tract, "$Id$"); SRCID(tract, "$Id$");
static void ChunkDecache(Arena arena, Chunk chunk);
/* TractArena -- get the arena of a tract */ /* TractArena -- get the arena of a tract */
#define TractArena(tract) PoolArena(TractPool(tract)) #define TractArena(tract) PoolArena(TractPool(tract))
@ -29,8 +37,10 @@ static void ChunkDecache(Arena arena, Chunk chunk);
Bool TractCheck(Tract tract) Bool TractCheck(Tract tract)
{ {
if (TractHasPool(tract)) {
CHECKU(Pool, TractPool(tract)); CHECKU(Pool, TractPool(tract));
CHECKL(AddrIsArenaGrain(TractBase(tract), TractArena(tract))); CHECKL(AddrIsArenaGrain(TractBase(tract), TractArena(tract)));
}
if (TractHasSeg(tract)) { if (TractHasSeg(tract)) {
CHECKL(TraceSetCheck(TractWhite(tract))); CHECKL(TraceSetCheck(TractWhite(tract)));
CHECKU(Seg, (Seg)TractP(tract)); CHECKU(Seg, (Seg)TractP(tract));
@ -91,13 +101,11 @@ Addr (TractBase)(Tract tract)
} }
/* TractLimit -- return the limit address of a segment */ /* TractLimit -- return the limit address of a tract */
Addr TractLimit(Tract tract) Addr TractLimit(Tract tract, Arena arena)
{ {
Arena arena;
AVERT_CRITICAL(Tract, tract); /* .tract.critical */ AVERT_CRITICAL(Tract, tract); /* .tract.critical */
arena = TractArena(tract);
AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Arena, arena);
return AddrAdd(TractBase(tract), ArenaGrainSize(arena)); return AddrAdd(TractBase(tract), ArenaGrainSize(arena));
} }
@ -113,17 +121,17 @@ Bool ChunkCheck(Chunk chunk)
CHECKS(Chunk, chunk); CHECKS(Chunk, chunk);
CHECKU(Arena, chunk->arena); CHECKU(Arena, chunk->arena);
CHECKL(chunk->serial < chunk->arena->chunkSerial); CHECKL(chunk->serial < chunk->arena->chunkSerial);
CHECKD_NOSIG(Ring, &chunk->chunkRing); /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */
CHECKL(TreeCheck(&chunk->chunkTree));
CHECKL(ChunkPagesToSize(chunk, 1) == ChunkPageSize(chunk)); CHECKL(ChunkPagesToSize(chunk, 1) == ChunkPageSize(chunk));
CHECKL(ShiftCheck(ChunkPageShift(chunk))); CHECKL(ShiftCheck(ChunkPageShift(chunk)));
CHECKL(chunk->base != (Addr)0); CHECKL(chunk->base != (Addr)0);
CHECKL(chunk->base < chunk->limit); CHECKL(chunk->base < chunk->limit);
/* check chunk is in itself */ /* check chunk structure is at its own base: see .chunk.at.base. */
CHECKL(chunk->base <= (Addr)chunk); CHECKL(chunk->base == (Addr)chunk);
CHECKL((Addr)(chunk+1) <= chunk->limit); CHECKL((Addr)(chunk+1) <= chunk->limit);
CHECKL(ChunkSizeToPages(chunk, AddrOffset(chunk->base, chunk->limit)) CHECKL(ChunkSizeToPages(chunk, ChunkSize(chunk)) == chunk->pages);
== chunk->pages);
/* check that the tables fit in the chunk */ /* check that the tables fit in the chunk */
CHECKL(chunk->allocBase <= chunk->pages); CHECKL(chunk->allocBase <= chunk->pages);
CHECKL(chunk->allocBase >= chunk->pageTablePages); CHECKL(chunk->allocBase >= chunk->pageTablePages);
@ -177,13 +185,12 @@ Res ChunkInit(Chunk chunk, Arena arena,
chunk->serial = (arena->chunkSerial)++; chunk->serial = (arena->chunkSerial)++;
chunk->arena = arena; chunk->arena = arena;
RingInit(&chunk->chunkRing); RingInit(&chunk->chunkRing);
RingAppend(&arena->chunkRing, &chunk->chunkRing);
chunk->pageSize = pageSize; chunk->pageSize = pageSize;
chunk->pageShift = pageShift = SizeLog2(pageSize); chunk->pageShift = pageShift = SizeLog2(pageSize);
chunk->base = base; chunk->base = base;
chunk->limit = limit; chunk->limit = limit;
size = AddrOffset(base, limit); size = ChunkSize(chunk);
chunk->pages = pages = size >> pageShift; chunk->pages = pages = size >> pageShift;
res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN); res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN);
@ -218,9 +225,13 @@ Res ChunkInit(Chunk chunk, Arena arena,
goto failLandInsert; goto failLandInsert;
} }
TreeInit(&chunk->chunkTree);
chunk->sig = ChunkSig; chunk->sig = ChunkSig;
AVERT(Chunk, chunk); AVERT(Chunk, chunk);
ArenaChunkInsert(arena, chunk);
/* As part of the bootstrap, the first created chunk becomes the primary /* As part of the bootstrap, the first created chunk becomes the primary
chunk. This step allows AreaFreeLandInsert to allocate pages. */ chunk. This step allows AreaFreeLandInsert to allocate pages. */
if (arena->primary == NULL) if (arena->primary == NULL)
@ -242,17 +253,23 @@ failAllocTable:
void ChunkFinish(Chunk chunk) void ChunkFinish(Chunk chunk)
{ {
AVERT(Chunk, chunk); Arena arena;
AVER(BTIsResRange(chunk->allocTable, 0, chunk->pages));
ChunkDecache(chunk->arena, chunk);
chunk->sig = SigInvalid;
RingRemove(&chunk->chunkRing);
if (ChunkArena(chunk)->hasFreeLand) AVERT(Chunk, chunk);
ArenaFreeLandDelete(ChunkArena(chunk),
AVER(BTIsResRange(chunk->allocTable, 0, chunk->pages));
arena = ChunkArena(chunk);
if (arena->hasFreeLand)
ArenaFreeLandDelete(arena,
PageIndexBase(chunk, chunk->allocBase), PageIndexBase(chunk, chunk->allocBase),
chunk->limit); chunk->limit);
chunk->sig = SigInvalid;
TreeFinish(&chunk->chunkTree);
RingRemove(&chunk->chunkRing);
if (chunk->arena->primary == chunk) if (chunk->arena->primary == chunk)
chunk->arena->primary = NULL; chunk->arena->primary = NULL;
@ -262,92 +279,40 @@ void ChunkFinish(Chunk chunk)
} }
/* Chunk Cache /* ChunkCompare -- Compare key to [base,limit) */
*
* Functions for manipulating the chunk cache in the arena.
*/
Compare ChunkCompare(Tree tree, TreeKey key)
/* ChunkCacheEntryCheck -- check a chunk cache entry
*
* The cache is EITHER empty:
* - chunk is null; AND
* - base & limit are both null
* OR full:
* - chunk is non-null, points to a ChunkStruct; AND
* - base & limit are not both null;
*
* .chunk.empty.fields: Fields of an empty cache are nonetheless read,
* and must be correct.
*/
Bool ChunkCacheEntryCheck(ChunkCacheEntry entry)
{ {
CHECKS(ChunkCacheEntry, entry); Addr base1, base2, limit2;
if (entry->chunk == NULL) { Chunk chunk;
CHECKL(entry->base == NULL); /* .chunk.empty.fields */
CHECKL(entry->limit == NULL); /* .chunk.empty.fields */
} else {
CHECKL(!(entry->base == NULL && entry->limit == NULL));
CHECKD(Chunk, entry->chunk);
CHECKL(entry->base == entry->chunk->base);
CHECKL(entry->limit == entry->chunk->limit);
}
return TRUE;
}
AVERT_CRITICAL(Tree, tree);
AVER_CRITICAL(tree != TreeEMPTY);
/* ChunkCacheEntryInit -- initialize a chunk cache entry */ /* See .chunk.at.base. */
chunk = ChunkOfTree(tree);
void ChunkCacheEntryInit(ChunkCacheEntry entry)
{
entry->chunk = NULL;
entry->base = NULL; /* .chunk.empty.fields */
entry->limit = NULL; /* .chunk.empty.fields */
entry->sig = ChunkCacheEntrySig;
AVERT(ChunkCacheEntry, entry);
return;
}
/* ChunkEncache -- cache a chunk */
static void ChunkEncache(Arena arena, Chunk chunk)
{
/* [Critical path](../design/critical-path.txt); called by ChunkOfAddr */
AVERT_CRITICAL(Arena, arena);
AVERT_CRITICAL(Chunk, chunk); AVERT_CRITICAL(Chunk, chunk);
AVER_CRITICAL(arena == chunk->arena);
AVERT_CRITICAL(ChunkCacheEntry, &arena->chunkCache);
/* check chunk already in cache first */ base1 = AddrOfTreeKey(key);
if (arena->chunkCache.chunk == chunk) { base2 = chunk->base;
return; limit2 = chunk->limit;
}
arena->chunkCache.chunk = chunk; if (base1 < base2)
arena->chunkCache.base = chunk->base; return CompareLESS;
arena->chunkCache.limit = chunk->limit; else if (base1 >= limit2)
return CompareGREATER;
AVERT_CRITICAL(ChunkCacheEntry, &arena->chunkCache); else
return; return CompareEQUAL;
} }
/* ChunkDecache -- make sure a chunk is not in the cache */ /* ChunkKey -- Return the key corresponding to a chunk */
static void ChunkDecache(Arena arena, Chunk chunk) TreeKey ChunkKey(Tree tree)
{ {
AVERT(Arena, arena); /* See .chunk.at.base. */
AVERT(Chunk, chunk); Chunk chunk = ChunkOfTree(tree);
AVER(arena == chunk->arena); return TreeKeyOfAddrVar(chunk);
AVERT(ChunkCacheEntry, &arena->chunkCache);
if (arena->chunkCache.chunk == chunk) {
arena->chunkCache.chunk = NULL;
arena->chunkCache.base = NULL; /* .chunk.empty.fields */
arena->chunkCache.limit = NULL; /* .chunk.empty.fields */
}
AVERT(ChunkCacheEntry, &arena->chunkCache);
} }
@ -355,77 +320,25 @@ static void ChunkDecache(Arena arena, Chunk chunk)
Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr) Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr)
{ {
Ring node, next; Tree tree;
AVER_CRITICAL(chunkReturn != NULL); AVER_CRITICAL(chunkReturn != NULL);
AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Arena, arena);
/* addr is arbitrary */ /* addr is arbitrary */
/* check cache first; see also .chunk.empty.fields */ if (TreeFind(&tree, ArenaChunkTree(arena), TreeKeyOfAddrVar(addr),
AVERT_CRITICAL(ChunkCacheEntry, &arena->chunkCache); ChunkCompare)
if (arena->chunkCache.base <= addr && addr < arena->chunkCache.limit) { == CompareEQUAL)
*chunkReturn = arena->chunkCache.chunk; {
AVER_CRITICAL(*chunkReturn != NULL); Chunk chunk = ChunkOfTree(tree);
return TRUE; AVER_CRITICAL(chunk->base <= addr && addr < chunk->limit);
}
RING_FOR(node, &arena->chunkRing, next) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node);
if (chunk->base <= addr && addr < chunk->limit) {
/* Gotcha! */
ChunkEncache(arena, chunk);
*chunkReturn = chunk; *chunkReturn = chunk;
return TRUE; return TRUE;
} }
}
return FALSE; return FALSE;
} }
/* ChunkOfNextAddr
*
* Finds the next higher chunk in memory which does _not_ contain addr.
* Returns FALSE if there is none.
*
* [The name is misleading; it should be "NextChunkAboveAddr" -- the
* word "Next" applies to chunks, not to addrs. RHSK 2010-03-20.]
*/
static Bool ChunkOfNextAddr(Chunk *chunkReturn, Arena arena, Addr addr)
{
Addr leastBase;
Chunk leastChunk;
Ring node, next;
leastBase = (Addr)(Word)-1;
leastChunk = NULL;
RING_FOR(node, &arena->chunkRing, next) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node);
if (addr < chunk->base && chunk->base < leastBase) {
leastBase = chunk->base;
leastChunk = chunk;
}
}
if (leastChunk != NULL) {
*chunkReturn = leastChunk;
return TRUE;
}
return FALSE;
}
/* ArenaIsReservedAddr -- is address managed by this arena? */
Bool ArenaIsReservedAddr(Arena arena, Addr addr)
{
Chunk dummy;
AVERT(Arena, arena);
/* addr is arbitrary */
return ChunkOfAddr(&dummy, arena, addr);
}
/* IndexOfAddr -- return the index of the page containing an address /* IndexOfAddr -- return the index of the page containing an address
* *
* Function version of INDEX_OF_ADDR, for debugging purposes. * Function version of INDEX_OF_ADDR, for debugging purposes.
@ -440,6 +353,24 @@ Index IndexOfAddr(Chunk chunk, Addr addr)
} }
/* ChunkNodeDescribe -- describe a single node in the tree of chunks,
* for SplayTreeDescribe
*/
Res ChunkNodeDescribe(Tree node, mps_lib_FILE *stream)
{
Chunk chunk;
if (!TreeCheck(node)) return ResFAIL;
if (stream == NULL) return ResFAIL;
chunk = ChunkOfTree(node);
if (!TESTT(Chunk, chunk)) return ResFAIL;
return WriteF(stream, 0, "[$P,$P)", (WriteFP)chunk->base,
(WriteFP)chunk->limit, NULL);
}
/* Page table functions */ /* Page table functions */
/* .tract.critical: These Tract functions are low-level and are on /* .tract.critical: These Tract functions are low-level and are on
@ -508,110 +439,6 @@ Tract TractOfBaseAddr(Arena arena, Addr addr)
} }
/* tractSearchInChunk -- search for a tract
*
* .tract-search: Searches for a tract in the chunk starting at page
* index i, return NULL if there is none. .tract-search.private: This
* function is private to this module and is used in the tract iteration
* protocol (TractFirst and TractNext).
*/
static Bool tractSearchInChunk(Tract *tractReturn, Chunk chunk, Index i)
{
AVER_CRITICAL(chunk->allocBase <= i);
AVER_CRITICAL(i <= chunk->pages);
while (i < chunk->pages
&& !(BTGet(chunk->allocTable, i)
&& PageIsAllocated(ChunkPage(chunk, i)))) {
++i;
}
if (i == chunk->pages)
return FALSE;
AVER(i < chunk->pages);
*tractReturn = PageTract(ChunkPage(chunk, i));
return TRUE;
}
/* tractSearch
*
* Searches for the next tract in increasing address order.
* The tract returned is the next one along from addr (i.e.,
* it has a base address bigger than addr and no other tract
* with a base address bigger than addr has a smaller base address).
*
* Returns FALSE if there is no tract to find (end of the arena).
*/
static Bool tractSearch(Tract *tractReturn, Arena arena, Addr addr)
{
Bool b;
Chunk chunk;
b = ChunkOfAddr(&chunk, arena, addr);
if (b) {
Index i;
i = INDEX_OF_ADDR(chunk, addr);
/* There are fewer pages than addresses, therefore the */
/* page index can never wrap around */
AVER_CRITICAL(i+1 != 0);
if (tractSearchInChunk(tractReturn, chunk, i+1)) {
return TRUE;
}
}
while (ChunkOfNextAddr(&chunk, arena, addr)) {
/* If the ring was kept in address order, this could be improved. */
addr = chunk->base;
/* Start from allocBase to skip the tables. */
if (tractSearchInChunk(tractReturn, chunk, chunk->allocBase)) {
return TRUE;
}
}
return FALSE;
}
/* TractFirst -- return the first tract in the arena
*
* This is used to start an iteration over all tracts in the arena, not
* including the ones used for page tables and other arena structures.
*/
Bool TractFirst(Tract *tractReturn, Arena arena)
{
AVER(tractReturn != NULL);
AVERT(Arena, arena);
/* .tractfirst.assume.nozero: We assume that there is no tract */
/* with base address (Addr)0. Happily this assumption is sound */
/* for a number of reasons. */
return tractSearch(tractReturn, arena, (Addr)0);
}
/* TractNext -- return the "next" tract in the arena
*
* TractNext finds the tract with the lowest base address which is
* greater than a specified address. The address must be (or once
* have been) the base address of a tract.
*
* This is used as the iteration step when iterating over all
* tracts in the arena.
*/
Bool TractNext(Tract *tractReturn, Arena arena, Addr addr)
{
AVER_CRITICAL(tractReturn != NULL); /* .tract.critical */
AVERT_CRITICAL(Arena, arena);
AVER_CRITICAL(AddrIsAligned(addr, ArenaGrainSize(arena)));
return tractSearch(tractReturn, arena, addr);
}
/* PageAlloc /* PageAlloc
* *
* Sets up the page descriptor for an allocated page to turn it into a Tract. * Sets up the page descriptor for an allocated page to turn it into a Tract.

View file

@ -9,8 +9,9 @@
#define tract_h #define tract_h
#include "mpmtypes.h" #include "mpmtypes.h"
#include "ring.h"
#include "bt.h" #include "bt.h"
#include "ring.h"
#include "tree.h"
/* Page states /* Page states
@ -50,8 +51,10 @@ typedef struct TractStruct { /* Tract structure */
extern Addr (TractBase)(Tract tract); extern Addr (TractBase)(Tract tract);
#define TractBase(tract) ((tract)->base) #define TractBase(tract) ((tract)->base)
extern Addr TractLimit(Tract tract); extern Addr TractLimit(Tract tract, Arena arena);
#define TractHasPool(tract) \
((tract)->pool.state == PageStateALLOC && TractPool(tract))
#define TractPool(tract) ((tract)->pool.pool) #define TractPool(tract) ((tract)->pool.pool)
#define TractP(tract) ((tract)->p) #define TractP(tract) ((tract)->p)
#define TractSetP(tract, pp) ((void)((tract)->p = (pp))) #define TractSetP(tract, pp) ((void)((tract)->p = (pp)))
@ -134,7 +137,8 @@ typedef struct ChunkStruct {
Sig sig; /* <design/sig/> */ Sig sig; /* <design/sig/> */
Serial serial; /* serial within the arena */ Serial serial; /* serial within the arena */
Arena arena; /* parent arena */ Arena arena; /* parent arena */
RingStruct chunkRing; /* ring of all chunks in arena */ RingStruct chunkRing; /* node in ring of all chunks in arena */
TreeStruct chunkTree; /* node in tree of all chunks in arena */
Size pageSize; /* size of pages */ Size pageSize; /* size of pages */
Shift pageShift; /* log2 of page size, for shifts */ Shift pageShift; /* log2 of page size, for shifts */
Addr base; /* base address of chunk */ Addr base; /* base address of chunk */
@ -148,31 +152,24 @@ typedef struct ChunkStruct {
#define ChunkArena(chunk) RVALUE((chunk)->arena) #define ChunkArena(chunk) RVALUE((chunk)->arena)
#define ChunkSize(chunk) AddrOffset((chunk)->base, (chunk)->limit)
#define ChunkPageSize(chunk) RVALUE((chunk)->pageSize) #define ChunkPageSize(chunk) RVALUE((chunk)->pageSize)
#define ChunkPageShift(chunk) RVALUE((chunk)->pageShift) #define ChunkPageShift(chunk) RVALUE((chunk)->pageShift)
#define ChunkPagesToSize(chunk, pages) ((Size)(pages) << (chunk)->pageShift) #define ChunkPagesToSize(chunk, pages) ((Size)(pages) << (chunk)->pageShift)
#define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift)) #define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift))
#define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi]) #define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi])
#define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree)
extern Bool ChunkCheck(Chunk chunk); extern Bool ChunkCheck(Chunk chunk);
extern Res ChunkInit(Chunk chunk, Arena arena, extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit,
Addr base, Addr limit, Align pageSize, BootBlock boot); Align pageSize, BootBlock boot);
extern void ChunkFinish(Chunk chunk); extern void ChunkFinish(Chunk chunk);
extern Compare ChunkCompare(Tree tree, TreeKey key);
extern TreeKey ChunkKey(Tree tree);
extern Bool ChunkCacheEntryCheck(ChunkCacheEntry entry); extern Bool ChunkCacheEntryCheck(ChunkCacheEntry entry);
extern void ChunkCacheEntryInit(ChunkCacheEntry entry); extern void ChunkCacheEntryInit(ChunkCacheEntry entry);
extern Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr); extern Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr);
extern Res ChunkNodeDescribe(Tree node, mps_lib_FILE *stream);
/* CHUNK_OF_ADDR -- return the chunk containing an address
*
* arena and addr are evaluated multiple times.
*/
#define CHUNK_OF_ADDR(chunkReturn, arena, addr) \
(((arena)->chunkCache.base <= (addr) && (addr) < (arena)->chunkCache.limit) \
? (*(chunkReturn) = (arena)->chunkCache.chunk, TRUE) \
: ChunkOfAddr(chunkReturn, arena, addr))
/* AddrPageBase -- the base of the page this address is on */ /* AddrPageBase -- the base of the page this address is on */
@ -186,25 +183,6 @@ extern Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr);
extern Tract TractOfBaseAddr(Arena arena, Addr addr); extern Tract TractOfBaseAddr(Arena arena, Addr addr);
extern Bool TractOfAddr(Tract *tractReturn, Arena arena, Addr addr); extern Bool TractOfAddr(Tract *tractReturn, Arena arena, Addr addr);
/* TRACT_OF_ADDR -- return the tract containing an address */
#define TRACT_OF_ADDR(tractReturn, arena, addr) \
BEGIN \
Arena _arena = (arena); \
Addr _addr = (addr); \
Chunk _chunk; \
Index _i; \
\
if (CHUNK_OF_ADDR(&_chunk, _arena, _addr)) { \
_i = INDEX_OF_ADDR(_chunk, _addr); \
if (BTGet(_chunk->allocTable, _i)) \
*(tractReturn) = PageTract(&_chunk->pageTable[_i]); \
else \
*(tractReturn) = NULL; \
} else \
*(tractReturn) = NULL; \
END
/* INDEX_OF_ADDR -- return the index of the page containing an address /* INDEX_OF_ADDR -- return the index of the page containing an address
* *
@ -235,15 +213,12 @@ extern Index IndexOfAddr(Chunk chunk, Addr addr);
Chunk _ch = NULL; \ Chunk _ch = NULL; \
\ \
UNUSED(_ch); \ UNUSED(_ch); \
AVER(ChunkOfAddr(&_ch, arena, rangeBase) && (rangeLimit) <= _ch->limit); \ AVER(ChunkOfAddr(&_ch, arena, rangeBase)); \
AVER((rangeLimit) <= _ch->limit); \
END END
extern Bool TractFirst(Tract *tractReturn, Arena arena); /* TRACT_TRACT_FOR -- iterate over a range of tracts in a chunk
extern Bool TractNext(Tract *tractReturn, Arena arena, Addr addr);
/* TRACT_TRACT_FOR -- iterate over a range of tracts
* *
* See <design/arena-tract-iter/#if.macro>. * See <design/arena-tract-iter/#if.macro>.
* Parameters arena & limit are evaluated multiple times. * Parameters arena & limit are evaluated multiple times.
@ -260,7 +235,7 @@ extern Bool TractNext(Tract *tractReturn, Arena arena, Addr addr);
(tract = NULL) /* terminate loop */)) (tract = NULL) /* terminate loop */))
/* TRACT_FOR -- iterate over a range of tracts /* TRACT_FOR -- iterate over a range of tracts in a chunk
* *
* See <design/arena/#tract.for>. * See <design/arena/#tract.for>.
* Parameters arena & limit are evaluated multiple times. * Parameters arena & limit are evaluated multiple times.

View file

@ -70,8 +70,6 @@ Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key)
} }
#if 0 /* This code is not currently in use in the MPS */
/* TreeFind -- search for a node matching the key /* TreeFind -- search for a node matching the key
* *
* If a matching node is found, sets *treeReturn to that node and returns * If a matching node is found, sets *treeReturn to that node and returns
@ -87,9 +85,9 @@ Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
Tree node, parent; Tree node, parent;
Compare cmp = CompareEQUAL; Compare cmp = CompareEQUAL;
AVERT(Tree, root); AVERT_CRITICAL(Tree, root);
AVER(treeReturn != NULL); AVER_CRITICAL(treeReturn != NULL);
AVER(FUNCHECK(compare)); AVER_CRITICAL(FUNCHECK(compare));
/* key is arbitrary */ /* key is arbitrary */
parent = NULL; parent = NULL;
@ -119,6 +117,49 @@ Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
} }
/* TreeFindNext -- search for node containing key, or next node
*
* If there is a node that is greater than key, set *treeReturn to that
* node and return TRUE.
*
* Otherwise, key is greater than all nodes in the tree, so leave
* *treeReturn unchanged and return FALSE.
*/
Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare)
{
Tree node, best = NULL;
Bool result = FALSE;
AVERT(Tree, root);
AVER(treeReturn != NULL);
AVER(FUNCHECK(compare));
/* key is arbitrary */
node = root;
while (node != TreeEMPTY) {
Compare cmp = compare(node, key);
switch (cmp) {
case CompareLESS:
best = node;
result = TRUE;
node = node->left;
break;
case CompareEQUAL:
case CompareGREATER:
node = node->right;
break;
default:
NOTREACHED;
return FALSE;
}
}
*treeReturn = best;
return result;
}
/* TreeInsert -- insert a node into a tree /* TreeInsert -- insert a node into a tree
* *
* If the key doesn't exist in the tree, inserts a node as a leaf of the * If the key doesn't exist in the tree, inserts a node as a leaf of the
@ -134,7 +175,7 @@ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
Compare cmp; Compare cmp;
AVER(treeReturn != NULL); AVER(treeReturn != NULL);
AVER(Tree, root); AVERT(Tree, root);
AVER(TreeCheckLeaf(node)); AVER(TreeCheckLeaf(node));
AVER(FUNCHECK(compare)); AVER(FUNCHECK(compare));
/* key is arbitrary */ /* key is arbitrary */
@ -166,6 +207,8 @@ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
} }
#if 0 /* This code is currently not in use in the MPS */
/* TreeTraverseMorris -- traverse tree inorder in constant space /* TreeTraverseMorris -- traverse tree inorder in constant space
* *
* The tree may not be accessed or modified during the traversal, and * The tree may not be accessed or modified during the traversal, and
@ -432,9 +475,6 @@ Tree TreeReverseRightSpine(Tree tree)
} }
#if 0 /* This code is currently not in use in the MPS */
/* TreeToVine -- unbalance a tree into a single right spine */ /* TreeToVine -- unbalance a tree into a single right spine */
Count TreeToVine(Tree *link) Count TreeToVine(Tree *link)
@ -488,7 +528,39 @@ void TreeBalance(Tree *treeIO)
} }
#endif /* not currently in use in the MPS */ /* TreeTraverseAndDelete -- traverse a tree while deleting nodes
*
* The visitor function must return TRUE to delete the current node,
* or FALSE to keep it.
*
* See <design/arena/#chunk.delete.tricky>.
*/
void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
void *closureP, Size closureS)
{
Tree *treeref = treeIO;
AVER(treeIO != NULL);
AVERT(Tree, *treeIO);
AVER(FUNCHECK(visitor));
/* closureP and closureS are arbitrary */
TreeToVine(treeIO);
while (*treeref != TreeEMPTY) {
Tree tree = *treeref; /* Current node. */
Tree *nextref = &tree->right; /* Location of pointer to next node. */
Tree next = *nextref; /* Next node. */
if ((*visitor)(tree, closureP, closureS)) {
/* Delete current node. */
*treeref = next;
} else {
/* Keep current node. */
treeref = nextref;
}
}
TreeBalance(treeIO);
}
/* C. COPYRIGHT AND LICENSE /* C. COPYRIGHT AND LICENSE

View file

@ -42,6 +42,17 @@ typedef Compare (*TreeCompare)(Tree tree, TreeKey key);
typedef TreeKey (*TreeKeyMethod)(Tree tree); typedef TreeKey (*TreeKeyMethod)(Tree tree);
/* When storing Addrs in a tree, it is fastest to cast the Addr
* directly to a TreeKey. This assumes that Addr and TreeKey are
* compatible, possibly breaking <design/type/#addr.use>. On an exotic
* platform where the types are not convertible, take the address of
* the variable in TreeKeyOfAddrVar, and dereference the address in
* AddrOfTreeKey.
*/
#define TreeKeyOfAddrVar(var) ((TreeKey)(var))
#define AddrOfTreeKey(key) ((Addr)(key))
/* TreeEMPTY -- the empty tree /* TreeEMPTY -- the empty tree
* *
* TreeEMPTY is the tree with no nodes, and hence unable to satisfy its * TreeEMPTY is the tree with no nodes, and hence unable to satisfy its
@ -53,6 +64,7 @@ typedef TreeKey (*TreeKeyMethod)(Tree tree);
#define TreeEMPTY ((Tree)0) #define TreeEMPTY ((Tree)0)
extern Bool TreeCheck(Tree tree); extern Bool TreeCheck(Tree tree);
extern Bool TreeCheckLeaf(Tree tree); extern Bool TreeCheckLeaf(Tree tree);
extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key); extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);
@ -104,6 +116,8 @@ extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);
extern Compare TreeFind(Tree *treeReturn, Tree root, extern Compare TreeFind(Tree *treeReturn, Tree root,
TreeKey key, TreeCompare compare); TreeKey key, TreeCompare compare);
extern Bool TreeFindNext(Tree *treeReturn, Tree root,
TreeKey key, TreeCompare compare);
extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node, extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node,
TreeKey key, TreeCompare compare); TreeKey key, TreeCompare compare);
@ -123,6 +137,8 @@ extern Tree TreeReverseRightSpine(Tree tree);
extern Count TreeToVine(Tree *treeIO); extern Count TreeToVine(Tree *treeIO);
extern void TreeBalance(Tree *treeIO); extern void TreeBalance(Tree *treeIO);
extern void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor,
void *closureP, Size closureS);
#endif /* tree_h */ #endif /* tree_h */

View file

@ -230,6 +230,48 @@ implementations of those methods which must be overridden. Instead
each abstract method is initialized to ``NULL``. each abstract method is initialized to ``NULL``.
Chunks
......
_`.chunk`: Each contiguous region of address space managed by the MPS
is represented by a *chunk*.
_`.chunk.tracts`: A chunk contains a table of tracts. See `.tract`_.
_`.chunk.lookup`: Looking of the chunk of an address is the first
step in the second-stage fix operation, and so on the critical path.
See `design.mps.critical-path`_.
.. _design.mps.critical-path: critical-path
_`.chunk.tree`: For efficient lookup, chunks are stored in a balanced
tree; ``arena->chunkTree`` points to the root of the tree. Operations
on this tree must ensure that the tree remains balanced, otherwise
performance degrades badly with many chunks.
_`.chunk.insert`: New chunks are inserted into the tree by calling
``ArenaChunkInsert()``. This calls ``TreeInsert()``, followed by
``TreeBalance()`` to ensure that the tree is balanced.
_`.chunk.delete`: There is no corresponding function
``ArenaChunkDelete()``. Instead, deletions from the chunk tree are
carried out by calling ``TreeToVine()``, iterating over the vine
(where deletion is possible, if care is taken) and then calling
``TreeBalance()`` on the remaining tree. The function
``TreeTraverseAndDelete()`` implements this.
_`.chunk.delete.justify`: This is because we don't have a function
that deletes an item from a balanced tree efficiently, and because all
functions that delete chunks do so in a loop over the chunks (so the
best we can do is O(*n*) time in any case).
_`.chunk.delete.tricky`: Deleting chunks from the chunk tree is tricky
in the virtual memory arena because ``vmChunkDestroy()`` unmaps the
memory containing the chunk, which includes the tree node. So the next
chunk must be looked up before deleting the current chunk. The function
``TreeTraverseAndDelete()`` ensures that this is done.
Tracts Tracts
...... ......
@ -272,16 +314,20 @@ use it for any purpose.
_`.tract.field.hasSeg`: The ``hasSeg`` bit-field is a Boolean which _`.tract.field.hasSeg`: The ``hasSeg`` bit-field is a Boolean which
indicates whether the ``p`` field is being used by the segment module. indicates whether the ``p`` field is being used by the segment module.
If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. See If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. See
design.mps.type.bool.bitfield for why this is declared using the `design.mps.type.bool.bitfield`_ for why this is declared using the
``BOOLFIELD`` macro. ``BOOLFIELD`` macro.
.. _design.mps.type.bool.bitfield: type#bool.bitfield
_`.tract.field.base`: The base field contains the base address of the _`.tract.field.base`: The base field contains the base address of the
memory represented by the tract. memory represented by the tract.
_`.tract.field.white`: The white bit-field indicates for which traces _`.tract.field.white`: The white bit-field indicates for which traces
the tract is white (`.req.fun.trans.white`_). This information is also the tract is white (`.req.fun.trans.white`_). This information is also
stored in the segment, but is duplicated here for efficiency during a stored in the segment, but is duplicated here for efficiency during a
call to ``TraceFix()`` (see design.mps.trace.fix). call to ``TraceFix()`` (see `design.mps.trace.fix`_).
.. _design.mps.trace.fix: trace#fix
_`.tract.limit`: The limit of the tract's memory may be determined by _`.tract.limit`: The limit of the tract's memory may be determined by
adding the arena grain size to the base address. adding the arena grain size to the base address.
@ -291,9 +337,8 @@ design.mps.arena.tract-iter(0).
``Bool TractOfAddr(Tract *tractReturn, Arena arena, Addr addr)`` ``Bool TractOfAddr(Tract *tractReturn, Arena arena, Addr addr)``
_`.tract.if.tractofaddr`: The function ``TractOfAddr()`` finds the tract _`.tract.if.tractofaddr`: The function ``TractOfAddr()`` finds the
corresponding to an address in memory. (See `.req.fun.trans`_.) tract corresponding to an address in memory. (See `.req.fun.trans`_.)
If ``addr`` is an address which has been allocated to some pool, then If ``addr`` is an address which has been allocated to some pool, then
``TractOfAddr()`` returns ``TRUE``, and sets ``*tractReturn`` to the ``TractOfAddr()`` returns ``TRUE``, and sets ``*tractReturn`` to the
tract corresponding to that address. Otherwise, it returns ``FALSE``. tract corresponding to that address. Otherwise, it returns ``FALSE``.
@ -301,10 +346,6 @@ This function is similar to ``TractOfBaseAddr()`` (see
design.mps.arena.tract-iter.if.contig-base) but serves a more general design.mps.arena.tract-iter.if.contig-base) but serves a more general
purpose and is less efficient. purpose and is less efficient.
_`.tract.if.TRACT_OF_ADDR`: ``TRACT_OF_ADDR()`` is a macro version of
``TractOfAddr()``. It's provided for efficiency during a call to
``TraceFix()`` (see design.mps.trace.fix.tractofaddr).
Control pool Control pool
............ ............

View file

@ -243,10 +243,10 @@ setter method which sets the rank set of a buffer. It is called from
``BufferSetRankSet()``. Clients should not need to define their own ``BufferSetRankSet()``. Clients should not need to define their own
methods for this. methods for this.
``typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream)`` ``typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream, Count depth)``
_`.class.method.describe`: ``describe()`` is a class-specific method _`.class.method.describe`: ``describe()`` is a class-specific method
called to describe a buffer, via BufferDescribe. Client-defined called to describe a buffer, via ``BufferDescribe()``. Client-defined
methods must call their superclass method (via a next-method call) methods must call their superclass method (via a next-method call)
before describing any class-specific state. before describing any class-specific state.

View file

@ -230,20 +230,21 @@ If a pointer gets past the first-stage fix filters, it is passed to
yet more pointers using information about segments before it has to yet more pointers using information about segments before it has to
consult the pool class. consult the pool class.
The first test applied is the "tract test". The MPS looks up the tract The first test is to determine if the address points to a *chunk* (a
containing the address in the tract table, which is a simple linear contiguous regions of address space managed by the arena). Addresses
table indexed by the address shifted -- a kind of flat page table. that do not point to any chunk (for example, ambiguous references that
are not in fact pointers) are rejected immediately.
Note that if the arena has been extended, the tract table becomes less When there are many chunks (that is, when the arena has been extended
simple, and this test may involved looking in more than one table. many times), this test can consume the majority of the garbage
This will cause a considerable slow-down in garbage collection collection time. This is the reason that it's important to give a good
scanning. This is the reason that it's important to give a good
estimate of the amount of address space you will ever occupy with estimate of the amount of address space you will ever occupy with
objects when you initialize the arena. objects when you initialize the arena.
The pointer might not even be in the arena (and so not in any tract). The second test applied is the "tract test". The MPS looks up the
The first stage fix doesn't guarantee it. So we eliminate any pointers tract containing the address in the tract table, which is a simple
not in the arena at this stage. linear table indexed by the address shifted -- a kind of flat page
table.
If the pointer is in an allocated tract, then the table also contains If the pointer is in an allocated tract, then the table also contains
a cache of the "white set" -- the set of garbage collection traces for a cache of the "white set" -- the set of garbage collection traces for

View file

@ -77,21 +77,23 @@ There are two mechanism for getting diagnostic output:
(gdb) frame 12 (gdb) frame 12
#12 0x000000010000b1fc in MVTFree (pool=0x103ffe160, base=0x101dfd000, size=5024) at poolmv2.c:711 #12 0x000000010000b1fc in MVTFree (pool=0x103ffe160, base=0x101dfd000, size=5024) at poolmv2.c:711
711 Res res = CBSInsert(MVTCBS(mvt), base, limit); 711 Res res = CBSInsert(MVTCBS(mvt), base, limit);
(gdb) p MVTDescribe(mvt, mps_lib_get_stdout()) (gdb) p MVTDescribe(mvt, mps_lib_get_stdout(), 0)
MVT 0000000103FFE160 MVT 0000000103FFE160 {
{
minSize: 8 minSize: 8
meanSize: 42 meanSize: 42
maxSize: 8192 maxSize: 8192
fragLimit: 30 fragLimit: 30
reuseSize: 16384 reuseSize: 16384
fillSize: 8192 fillSize: 8192
availLimit: 1110835 availLimit: 90931
abqOverflow: FALSE abqOverflow: FALSE
splinter: TRUE splinter: TRUE
splinterSeg: 0000000103FEE780 splinterBase: 0000000106192FF0
splinterBase: 0000000101D7ABB8 splinterLimit: 0000000106193000
splinterLimit: 0000000101D7B000 size: 303104
allocated: 262928
available: 40176
unavailable: 0
# ... etc ... # ... etc ...
} }

View file

@ -511,7 +511,10 @@ requested (to allow for large objects).
_`.arch.chunk`: Arenas may allocate more address space in additional _`.arch.chunk`: Arenas may allocate more address space in additional
chunks, which may be disjoint from the existing chunks. Inter-chunk chunks, which may be disjoint from the existing chunks. Inter-chunk
space will be represented by dummy regions. There are also sentinel space will be represented by dummy regions. There are also sentinel
regions at both ends of the address space. regions at both ends of the address space. See
`design.mps.arena.chunk`_.
.. _design.mps.arena.chunk: arena#chunk
Overview of strategy Overview of strategy

View file

@ -451,7 +451,7 @@ objects. Now reclaim doesn't need to check that the objects are
allocated before skipping them. There may be a corresponding change allocated before skipping them. There may be a corresponding change
for scan as well. for scan as well.
``Res AWLDescribe(Pool pool, mps_lib_FILE *stream)`` ``Res AWLDescribe(Pool pool, mps_lib_FILE *stream, Count depth)``
_`.fun.describe`: _`.fun.describe`:

View file

@ -471,11 +471,12 @@ required.
See analysis.mps.poolmrg.improve.scan.nomove for a suggested See analysis.mps.poolmrg.improve.scan.nomove for a suggested
improvement that avoids redundant unlinking and relinking. improvement that avoids redundant unlinking and relinking.
``Res MRGDescribe(Pool pool, mps_lib_FILE *stream)`` ``Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth)``
_`.describe`: Describes an MRG pool. Iterates along each of the entry _`.describe`: Describes an MRG pool. Iterates along each of the entry
and exit lists and prints the guardians in each. The location of the and exit lists and prints the guardians in each. The location of the
guardian and the value of the reference in it will be printed out. guardian and the value of the reference in it will be printed out.
Provided for debugging only.
_`.functions.unused`: All of these will be unused: ``BufferInit()``, _`.functions.unused`: All of these will be unused: ``BufferInit()``,
``BufferFill()``, ``BufferEmpty()``, ``BufferFinish()``, ``BufferFill()``, ``BufferEmpty()``, ``BufferFinish()``,

View file

@ -40,85 +40,24 @@ allocation can be used at the same time, but in that case, the first
ap must be created before any allocations. ap must be created before any allocations.
_`.over.buffer.class`: The pool uses the simplest buffer class, _`.over.buffer.class`: The pool uses the simplest buffer class,
BufferClass. This is appropriate since these buffers don't attach to ``BufferClass``. This is appropriate since these buffers don't attach
segments, and hence don't constrain buffered regions to lie within to segments, and hence don't constrain buffered regions to lie within
segment boundaries. segment boundaries.
_`.over.segments`: The pool uses the simplest segment class
(SegClass). There's no need for anything more complex.
Methods Methods
------- -------
_`.method`: The MVFF pool supports the following methods:
``Res MVFFInit(Pool pool, Args arg)``
_`.method.init`: This takes six `keyword arguments`_:
.. _`keyword arguments`: keyword-arguments
================================== ============================================
Keyword argument Description
================================== ============================================
``MPS_KEY_EXTEND_BY`` The segment size.
``MPS_KEY_MEAN_SIZE`` The average object size.
``MPS_KEY_ALIGN`` The alignment of allocations and frees.
Must be at least ``sizeof(void *)``.
``MPS_KEY_MVFF_SLOT_HIGH`` Whether to allocate objects at the end of
free blocks found, as opposed to at
the start (for unbuffered
allocation).
``MPS_KEY_MVFF_ARENA_HIGH`` Whether to express ``SegPrefHIGH``
to the arena, as opposed to
``SegPrefLOW``.
``MPS_KEY_MVFF_FIRST_FIT`` whether to use the suitable block of lowest
address, as opposed to the highest
(for unbuffered allocation)
================================== ============================================
_`.method.init.epdl`: To simulate the EPDL pool, specify ``extendBy``,
``avgSize``, and ``maxSize`` as normal, and use ``slotHigh=FALSE``,
``arenaHigh=FALSE``, ``firstFit=TRUE``.
_`.method.init.epdr`: To simulate the EPDR pool, specify ``extendBy``,
``avgSize``, and ``maxSize`` as normal, and use ``slotHigh=TRUE``,
``arenaHigh=TRUE``, ``firstFit=TRUE``.
_`.method.init.other`: The performance characteristics of other
combinations are unknown.
_`.method.finish`: The ``PoolFinish()`` method,
_`.method.alloc`: ``PoolAlloc()`` and ``PoolFree()`` methods are
supported, implementing the policy set by the pool params (see
`.method.init`_).
_`.method.describe`: The usual describe method.
_`.method.buffer`: The buffer methods implement a worst-fit fill _`.method.buffer`: The buffer methods implement a worst-fit fill
strategy. strategy.
External Functions
------------------
_`.function`: MVFF supports the following external functions:
_`.function.free-size`: ``mps_mvff_free_size()`` returns the total
size of free space in segments allocated to the MVFF pool instance.
_`.function.size`: ``mps_mvff_size()`` returns the total memory used
by pool segments, whether free or allocated.
_`.function.class`: ``mps_class_mvff()`` returns the class object for
the pool class, to be used in pool creation.
Implementation Implementation
-------------- --------------
_`.impl.alloc_list`: The pool stores the address ranges that it has
acquired from the arena in a CBS (see design.mps.cbs_).
_`.impl.free-list`: The pool stores its free list in a CBS (see _`.impl.free-list`: The pool stores its free list in a CBS (see
design.mps.cbs_), failing over in emergencies to a Freelist (see design.mps.cbs_), failing over in emergencies to a Freelist (see
design.mps.freelist_) when the CBS cannot allocate new control design.mps.freelist_) when the CBS cannot allocate new control
@ -131,13 +70,14 @@ structures. This is the reason for the alignment restriction above.
Details Details
------- -------
_`.design.seg-size`: When adding a segment, we use extendBy as the _`.design.acquire-size`: When acquiring memory from the arena, we use
segment size unless the object won't fit, in which case we use the ``extendBy`` as the unit of allocation unless the object won't fit, in
object size (in both cases we align up). which case we use the object size (in both cases we align up to the
arena alignment).
_`.design.seg-fail`: If allocating a segment fails, we try again with _`.design.acquire-fail`: If allocating ``extendBy``, we try again with
a segment size just large enough for the object we're allocating. This an aligned size just large enough for the object we're allocating.
is in response to request.mps.170186_. This is in response to request.mps.170186_.
.. _request.mps.170186: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/170186 .. _request.mps.170186: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/170186
@ -162,6 +102,12 @@ Document History
- 2013-06-04 GDR_ The CBS module no longer maintains its own emergency - 2013-06-04 GDR_ The CBS module no longer maintains its own emergency
list, so MVFF handles the fail-over from its CBS to a Freelist. list, so MVFF handles the fail-over from its CBS to a Freelist.
- 2014-04-15 GDR_ The address ranges acquired from the arena are now
stored in a CBS; segments are no longer used for this purpose.
- 2014-06-12 GDR_ Remove public interface documentation (this is in
the reference manual).
.. _RB: http://www.ravenbrook.com/consultants/rb/ .. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/

View file

@ -19,8 +19,8 @@ Scanned summary
............... ...............
_`.summary.subset`: The summary of reference seens by scan _`.summary.subset`: The summary of reference seens by scan
(ss.unfixedSummary) is a subset of the summary previously computed (``ss.unfixedSummary``) is a subset of the summary previously computed
(SegSummary). (``SegSummary()``).
There are two reasons that it is not an equality relation: There are two reasons that it is not an equality relation:
@ -34,9 +34,11 @@ There are two reasons that it is not an equality relation:
#. A write barrier hit will set the summary to ``RefSetUNIV``. #. A write barrier hit will set the summary to ``RefSetUNIV``.
The reason that ss.unfixedSummary is always a subset of the previous The reason that ``ss.unfixedSummary`` is always a subset of the
summary is due to an "optimization" which has not been made in previous summary is due to an "optimization" which has not been made
``TraceFix``. See impl.c.trace.fix.fixed.all. in ``TraceFix``. See `design.mps.trace.fix.fixed.all`_.
.. _design.mps.trace.fix.fixed.all: trace#fix.fixed.all
Partial scans Partial scans
@ -54,8 +56,8 @@ partial scans of condemned segments contribute to the segment summary.
_`.clever-summary.acc`: Each time we partially scan a segment, we _`.clever-summary.acc`: Each time we partially scan a segment, we
accumulate the post-scan summary of the scanned objects into a field accumulate the post-scan summary of the scanned objects into a field
in the group, called 'summarySoFar'. The post-scan summary is (summary in the group, called ``summarySoFar``. The post-scan summary is
\ white) U fixed. (summary \ white) fixed.
_`.clever-summary.acc.condemn`: The cumulative summary is only _`.clever-summary.acc.condemn`: The cumulative summary is only
meaningful while the segment is condemned. Otherwise it is set to meaningful while the segment is condemned. Otherwise it is set to

View file

@ -63,21 +63,20 @@ Data Structure
The implementations are as follows:: The implementations are as follows::
typedef struct SegStruct { /* segment structure */ typedef struct SegStruct { /* segment structure */
Sig sig; /* impl.h.misc.sig */ Sig sig; /* <code/misc.h#sig> */
SegClass class; /* segment class structure */ SegClass class; /* segment class structure */
Tract firstTract; /* first tract of segment */ Tract firstTract; /* first tract of segment */
RingStruct poolRing; /* link in list of segs in pool */ RingStruct poolRing; /* link in list of segs in pool */
Addr limit; /* limit of segment */ Addr limit; /* limit of segment */
unsigned depth : SHIELD_DEPTH_WIDTH; /* see impl.c.shield.def.depth */ unsigned depth : ShieldDepthWIDTH; /* see <code/shield.c#def.depth> */
AccessSet pm : AccessMAX; /* protection mode, impl.c.shield */ AccessSet pm : AccessLIMIT; /* protection mode, <code/shield.c> */
AccessSet sm : AccessMAX; /* shield mode, impl.c.shield */ AccessSet sm : AccessLIMIT; /* shield mode, <code/shield.c> */
TraceSet grey : TRACE_MAX; /* traces for which seg is grey */ TraceSet grey : TraceLIMIT; /* traces for which seg is grey */
TraceSet white : TRACE_MAX; /* traces for which seg is white */ TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TRACE_MAX; /* traces for which seg has nailed objects */ TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
RankSet rankSet : RankMAX; /* ranks of references in this seg */ RankSet rankSet : RankLIMIT; /* ranks of references in this seg */
} SegStruct; } SegStruct;
typedef struct GCSegStruct { /* GC segment structure */ typedef struct GCSegStruct { /* GC segment structure */
SegStruct segStruct; /* superclass fields must come first */ SegStruct segStruct; /* superclass fields must come first */
RingStruct greyRing; /* link in list of grey segs */ RingStruct greyRing; /* link in list of grey segs */

View file

@ -190,7 +190,7 @@ _`.type.tree.describe.method`: A function of type
``TreeDescribeMethod`` is required to write (via ``WriteF()``) a ``TreeDescribeMethod`` is required to write (via ``WriteF()``) a
client-oriented representation of the splay node. The output should be client-oriented representation of the splay node. The output should be
non-empty, short, and without newline characters. This is provided for non-empty, short, and without newline characters. This is provided for
debugging purposes only. debugging only.
Functions Functions
@ -340,12 +340,13 @@ _`.function.splay.tree.next`: If the tree contains a right neighbour
for ``key``, splay the tree at that node and return it. Otherwise for ``key``, splay the tree at that node and return it. Otherwise
return ``TreeEMPTY``. See `.req.iterate`_. return ``TreeEMPTY``. See `.req.iterate`_.
``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, TreeDescribeMethod nodeDescribe)`` ``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, TreeDescribeMethod nodeDescribe)``
_`.function.splay.tree.describe`: Print (using ``WriteF``) a textual _`.function.splay.tree.describe`: This function prints (using
representation of the given splay tree to the stream, using ``WriteF()``) to the stream a textual representation of the given
``nodeDescribe`` to print client-oriented representations of the nodes splay tree, using ``nodeDescribe`` to print client-oriented
(see `.req.debug`_). representations of the nodes (see `.req.debug`_). Provided for
debugging only.
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)`` ``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)``
@ -386,19 +387,19 @@ _`.prop`: To support `.req.property.find`_, this splay tree
implementation provides additional features to permit clients to cache implementation provides additional features to permit clients to cache
maximum (or minimum) values of client properties for all the nodes in maximum (or minimum) values of client properties for all the nodes in
a subtree. The splay tree implementation uses the cached values as a subtree. The splay tree implementation uses the cached values as
part of ``SplayFindFirst`` and ``SplayFindLast`` via the ``testNode`` part of ``SplayFindFirst()`` and ``SplayFindLast()`` via the
and ``testTree`` methods. The client is free to choose how to ``testNode`` and ``testTree`` methods. The client is free to choose
represent the client property, and how to compute and store the cached how to represent the client property, and how to compute and store the
value. cached value.
_`.prop.update`: The cached values depend upon the topology of the _`.prop.update`: The cached values depend upon the topology of the
tree, which may vary as a result of operations on the tree. The client tree, which may vary as a result of operations on the tree. The client
is given the opportunity to compute new cache values whenever is given the opportunity to compute new cache values whenever
necessary, via the ``updateNode`` method (see necessary, via the ``updateNode`` method (see
`.function.splay.tree.init`_). This happens whenever the tree is `.function.splay.tree.init`_). This happens whenever the tree is
restructured. The client may use the ``SplayNodeRefresh`` method to restructured. The client may use the ``SplayNodeRefresh()`` method to
indicate that the client attributes at a node have changed (see indicate that the client attributes at a node have changed (see
`.req.property.change`_). A call to ``SplayNodeRefresh`` splays the `.req.property.change`_). A call to ``SplayNodeRefresh()`` splays the
tree at the specified node, which may provoke calls to the tree at the specified node, which may provoke calls to the
``updateNode`` method as a result of the tree restructuring. The ``updateNode`` method as a result of the tree restructuring. The
``updateNode`` method will also be called whenever a new splay node is ``updateNode`` method will also be called whenever a new splay node is

View file

@ -409,7 +409,7 @@ _`.debug.dump`: The contents of all buffers can be dumped with the
_`.debug.describe`: Individual events can be described with the _`.debug.describe`: Individual events can be described with the
EventDescribe function, for example:: EventDescribe function, for example::
gdb> print EventDescribe(EventLast[3], mps_lib_get_stdout()) gdb> print EventDescribe(EventLast[3], mps_lib_get_stdout(), 0)
_`.debug.core`: The event buffers are preserved in core dumps and can _`.debug.core`: The event buffers are preserved in core dumps and can
be used to work out what the MPS was doing before a crash. Since the be used to work out what the MPS was doing before a crash. Since the

View file

@ -25,15 +25,16 @@ Introduction
Architecture Architecture
------------ ------------
_`.instance.limit`: There will be a limit on the number of traces that _`.instance.limit`: There is a limit on the number of traces that can
can be created at any one time. This effectively limits the number of be created at any one time. This limits the number of concurrent
concurrent traces. This limitation is expressed in the symbol traces. This limitation is expressed in the symbol ``TraceLIMIT``.
``TRACE_MAX``.
.. note:: .. note::
``TRACE_MAX`` is currently set to 1, see request.mps.160020_ ``TraceLIMIT`` is currently set to 1 as the MPS assumes in various
"Multiple traces would not work". David Jones, 1998-06-15. places that only a single trace is active at a time. See
request.mps.160020_ "Multiple traces would not work". David Jones,
1998-06-15.
.. _request.mps.160020: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160020 .. _request.mps.160020: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160020
@ -46,26 +47,32 @@ _`.rate`: See `mail.nickb.1997-07-31.14-37 </project/mps/mail/1997/07/31/14-37/0
.. _request.epcore.160062: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/160062 .. _request.epcore.160062: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/160062
_`.exact.legal`: Exact references should either point outside the _`.exact.legal`: Exact references must either point outside the arena
arena (to non-managed address space) or to a tract allocated to a (to non-managed address space) or to a tract allocated to a pool.
pool. Exact references that are to addresses which the arena has Exact references that are to addresses which the arena has reserved
reserved but hasn't allocated memory to are illegal (the exact but hasn't allocated memory to are illegal (such a reference cannot
reference couldn't possibly refer to a real object). Depending on the possibly refer to a real object, and so cannot be exact). We check
future semantics of ``PoolDestroy()`` we might need to adjust our that this is the case in ``TraceFix()``.
strategy here. See mail.dsm.1996-02-14.18-18 for a strategy of coping
gracefully with ``PoolDestroy()``. We check that this is the case in the
fixer. It may be sensible to make this check CRITICAL in certain
configurations.
_`.fix.fixed.all`: ``ss->fixedSummary`` is accumulated (in the fixer) .. note::
for all the pointers whether or not they are genuine references. We
could accumulate fewer pointers here; if a pointer fails the Depending on the future semantics of ``PoolDestroy()`` we might
``TractOfAddr()`` test then we know it isn't a reference, so we needn't need to adjust our strategy here. See `mail.dsm.1996-02-14.18-18`_
accumulate it into the fixed summary. The design allows this, but it for a strategy of coping gracefully with ``PoolDestroy()``.
breaks a useful post-condition on scanning (if the accumulation of
``ss->fixedSummary`` was moved the accuracy of ``ss->fixedSummary`` .. _mail.dsm.1996-02-14.18-18: https://info.ravenbrook.com/project/mps/mail/1996/02/14/18-18/0.txt
would vary according to the "width" of the white summary). See
mail.pekka.1998-02-04.16-48 for improvement suggestions. _`.fix.fixed.all`: ``ss->fixedSummary`` is accumulated (in
``TraceFix()``) for all pointers, whether or not they are genuine
references. We could accumulate fewer pointers here; if a pointer
fails the ``TractOfAddr()`` test then we know it isn't a reference, so
we needn't accumulate it into the fixed summary. The design allows
this, but it breaks a useful post-condition on scanning (if the
accumulation of ``ss->fixedSummary`` was moved the accuracy of
``ss->fixedSummary`` would vary according to the "width" of the white
summary). See `mail.pekka.1998-02-04.16-48`_ for improvement suggestions.
.. _mail.pekka.1998-02-04.16-48: https://info.ravenbrook.com/project/mps/mail/1998/02/04/16-48/0.txt
Analysis Analysis
@ -81,6 +88,7 @@ memory for copying.
.. _request.dylan.170560: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/170560 .. _request.dylan.170560: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/170560
Ideas Ideas
----- -----
@ -96,30 +104,56 @@ Implementation
Speed Speed
..... .....
_`.fix`: The fix path is critical to garbage collection speed. _`.fix`: The function implementing the fix operation should be called
Abstractly fix is applied to all the references in the non-white heap ``TraceFix()`` and this name is pervasive in the MPS and its documents
and all the references in the copied heap. Remembered sets cut down to describe this function. Nonethless, optimisation and strict
the number of segments we have to scan. The zone test cuts down the aliasing rules have meant that we need to use the external name for
number of references we call fix on. The speed of the remainder of the it, ``_mps_fix2()``.
fix path is still critical to system performance. Various
modifications to and aspects of the system are concerned with
maintaining the speed along this path.
_`.fix.tractofaddr`: ``TractOfAddr()`` is called on every reference that _`.fix.speed`: The fix path is critical to garbage collection speed.
passes the zone test and is on the critical path, to determine whether Abstractly, the fix operation is applied to all references in the
the segment is white. There is no need to examine the segment to non-white heap and all references in the copied heap. Remembered sets
perform this test, since whiteness information is duplicated in cut down the number of segments we have to scan. The zone test cuts
tracts, specifically to optimize this test. ``TractOfAddr()`` itself is down the number of references we call fix on. The speed of the
a simple class dispatch function (which dispatches to the arena remainder of the fix path is still critical to system performance.
class's ``TractOfAddr()`` method). Inlining the dispatch and inlining Various modifications to and aspects of the system are concerned with
the functions called by ``VMTractOfAddr()`` makes a small but noticable maintaining the speed along this path. See
difference to the speed of the dylan compiler. `design.mps.critical_path`_.
.. _design.mps.critical_path: critical_path
_`.fix.tractofaddr`: A reference that passes the zone test is then
looked up to find the tract it points to, an operation equivalent to
calling ``TractOfAddr()``.
_`.fix.tractofaddr.inline`: ``TraceFix()`` doesn't actually call
``TractOfAddr()``. Instead, it expands this operation inline (calling
``ChunkOfAddr()``, then ``INDEX_OF_ADDR()``, checking the appropriate
bit in the chunk's ``allocTable``, and finally looking up the tract in
the chunk's page table). The reason for inlining this code is that we
need to know whether the reference points to a chunk (and not just
whether it points to a tract) in order to check the `.exact.legal`_
condition.
_`.fix.whiteseg`: The reason for looking up the tract is to determine
whether the segment is white. There is no need to examine the segment
to perform this test, since whiteness information is duplicated in
tracts, specifically to optimize this test.
.. note::
Nonetheless, it is likely to be more efficient to maintain a
separate lookup table from address to white segment, rather than
indirecting through the chunk and the tract. See job003796_.
.. _job003796: http://www.ravenbrook.com/project/mps/issue/job003796/
_`.fix.noaver`: ``AVER()`` statements in the code add bulk to the code _`.fix.noaver`: ``AVER()`` statements in the code add bulk to the code
(reducing I-cache efficacy) and add branches to the path (polluting (reducing I-cache efficacy) and add branches to the path (polluting
the branch pedictors) resulting in a slow down. Removing all the the branch pedictors) resulting in a slow down. Replacing the
``AVER()`` statements from the fix path improves the overall speed of ``AVER()`` statements with ``AVER_CRITICAL()`` on the critical path
the Dylan compiler by as much as 9%. improves the overall speed of the Dylan compiler by as much as 9%. See
`design.mps.critical_path`_.
_`.fix.nocopy`: ``AMCFix()`` used to copy objects by using the format's _`.fix.nocopy`: ``AMCFix()`` used to copy objects by using the format's
copy method. This involved a function call (through an indirection) copy method. This involved a function call (through an indirection)
@ -131,19 +165,15 @@ inlined by the C compiler. This change results in a 45% speed-up in
the Dylan compiler. the Dylan compiler.
_`.reclaim`: Because the reclaim phase of the trace (implemented by _`.reclaim`: Because the reclaim phase of the trace (implemented by
``TraceReclaim()``) examines every segment it is fairly time intensive. ``TraceReclaim()``) examines every segment it is fairly time
rit's profiles presented in request.dylan.170551_ show a gap between intensive. Richard Tucker's profiles presented in
the two varieties variety.hi and variety.wi. request.dylan.170551_ show a gap between the two varieties variety.hi
and variety.wi.
.. _request.dylan.170551: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/170551 .. _request.dylan.170551: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/170551
_`.reclaim.noaver`: Converting ``AVER()`` statements in the loops of _`.reclaim.noaver`: Accordingly, reclaim methods use
``TraceReclaim()``, ``PoolReclaim()``, ``AMCReclaim()`` (``LOReclaim()``? ``AVER_CRITICAL()`` instead of ``AVER()``.
``AWLReclaim()``?) will result in a noticeable speed improvement.
.. note::
Insert actual speed improvement here, if any.
Life cycle of a trace object Life cycle of a trace object

View file

@ -579,9 +579,11 @@ space as the client data.
``typedef unsigned TraceId`` ``typedef unsigned TraceId``
_`.traceid`: A ``TraceId`` is an unsigned integer which is less than _`.traceid`: A ``TraceId`` is an unsigned integer which is less than
``TRACE_MAX``. Each running trace has a different ``TraceId`` which is ``TraceLIMIT``. Each running trace has a different ``TraceId`` which
used to index into tables and bitfields used to remember the state of is used to index into the tables and bitfields that record the state
that trace. of that trace. See `design.mps.trace.instance.limit`_.
.. _design.mps.trace.instance.limit: trace#instance.limit
``typedef unsigned TraceSet`` ``typedef unsigned TraceSet``

View file

@ -34,37 +34,52 @@ depends on ``fputc()`` and ``fputs()``, via the Library Interface
freestanding environment. This is achieved by implementing our own freestanding environment. This is achieved by implementing our own
internal output routines in mpm.c. internal output routines in mpm.c.
Our output requirements are few, so the code is short. The only output _`.writef`: Our output requirements are few, so the code is short. The
function which should be used in the rest of the MPM is ``WriteF()``, only output function which should be used in the rest of the MPM is
which is similar to ``fprintf()``: ``WriteF()``.
``Res WriteF(mps_lib_FILE *stream, ...)`` ``Res WriteF(mps_lib_FILE *stream, Count depth, ...)``
If ``depth`` is greater than zero, then the first format character,
and each format character after a newline, is preceded by ``depth``
spaces.
``WriteF()`` expects a format string followed by zero or more items to ``WriteF()`` expects a format string followed by zero or more items to
insert into the output, followed by another format string, more items, insert into the output, followed by another format string, more items,
and so on, and finally a ``NULL`` format string. For example:: and so on, and finally a ``NULL`` format string. For example::
WriteF(stream, res = WriteF(stream, depth,
"Hello: $A\n", address, "Hello: $A\n", address,
"Spong: $U ($S)\n", number, string, "Spong: $U ($S)\n", number, string,
NULL); NULL);
if (res != ResOK) return res;
This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` might contain the following code:: This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code::
WriteF(stream, res = WriteF(stream, depth,
"Buffer $P ($U) {\n", (WriteFP)buffer, (WriteFU)buffer->serial, "Buffer $P ($U) {\n",
" base $A init $A alloc $A limit $A\n", (WriteFP)buffer, (WriteFU)buffer->serial,
(WriteFA)buffer->base, (WriteFA)buffer->ap.init, " class $P (\"$S\")\n",
(WriteFA)buffer->ap.alloc, (WriteFA)buffer->ap.limit, (WriteFP)buffer->class, buffer->class->name,
" Arena $P\n", (WriteFP)buffer->arena,
" Pool $P\n", (WriteFP)buffer->pool, " Pool $P\n", (WriteFP)buffer->pool,
" Seg $P\n", (WriteFP)buffer->seg, " ", buffer->isMutator ? "Mutator" : "Internal", " Buffer\n",
" rank $U\n", (WriteFU)buffer->rank, " mode $C$C$C$C (TRANSITION, LOGGED, FLIPPED, ATTACHED)\n",
(WriteFC)((buffer->mode & BufferModeTRANSITION) ? 't' : '_'),
(WriteFC)((buffer->mode & BufferModeLOGGED) ? 'l' : '_'),
(WriteFC)((buffer->mode & BufferModeFLIPPED) ? 'f' : '_'),
(WriteFC)((buffer->mode & BufferModeATTACHED) ? 'a' : '_'),
" fillSize $UKb\n", (WriteFU)(buffer->fillSize / 1024),
" emptySize $UKb\n", (WriteFU)(buffer->emptySize / 1024),
" alignment $W\n", (WriteFW)buffer->alignment, " alignment $W\n", (WriteFW)buffer->alignment,
" grey $B\n", (WriteFB)buffer->grey, " base $A\n", buffer->base,
" shieldMode $B\n", (WriteFB)buffer->shieldMode, " initAtFlip $A\n", buffer->initAtFlip,
" p $P i $U\n", (WriteFP)buffer->p, (WriteFU)buffer->i, " init $A\n", buffer->ap_s.init,
"} Buffer $P ($U)\n", (WriteFP)buffer, (WriteFU)buffer->serial, " alloc $A\n", buffer->ap_s.alloc,
" limit $A\n", buffer->ap_s.limit,
" poolLimit $A\n", buffer->poolLimit,
NULL); NULL);
if (res != ResOK) return res;
_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a _`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a
type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted
@ -79,7 +94,7 @@ used in future in some generalisation of varargs in the MPS.
_`.formats`: The formats supported are as follows. _`.formats`: The formats supported are as follows.
======= =========== ================== ====================================== ======= =========== ================== ======================================
Code Bame Type Example rendering Code Name Type Example rendering
======= =========== ================== ====================================== ======= =========== ================== ======================================
``$A`` address ``Addr`` ``000000019EF60010`` ``$A`` address ``Addr`` ``000000019EF60010``
``$P`` pointer ``void *`` ``000000019EF60100`` ``$P`` pointer ``void *`` ``000000019EF60100``
@ -97,8 +112,8 @@ promotion of a ``char`` (see `.types`_).
_`.snazzy`: We should resist the temptation to make ``WriteF()`` an _`.snazzy`: We should resist the temptation to make ``WriteF()`` an
incredible snazzy output engine. We only need it for ``Describe()`` incredible snazzy output engine. We only need it for ``Describe()``
methods and assertion messages. At the moment it's a very simple bit methods. At the moment it's a simple bit of code -- let's keep it that
of code -- let's keep it that way. way.
_`.f`: The ``F`` code is used for function pointers. ISO C forbids casting _`.f`: The ``F`` code is used for function pointers. ISO C forbids casting
function pointers to other types, so the bytes of their representation are function pointers to other types, so the bytes of their representation are
@ -115,6 +130,8 @@ Document History
- 2013-05-22 GDR_ Converted to reStructuredText. - 2013-05-22 GDR_ Converted to reStructuredText.
- 2014-04-17 GDR_ ``WriteF()`` now takes a ``depth`` parameter.
.. _RB: http://www.ravenbrook.com/consultants/rb/ .. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/

View file

@ -37,6 +37,7 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <getopt.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
@ -409,6 +410,7 @@ static void error(const char *format, ...)
if (error_handler) { if (error_handler) {
longjmp(*error_handler, 1); longjmp(*error_handler, 1);
} else { } else {
fflush(stdout);
fprintf(stderr, "Fatal error during initialization: %s\n", fprintf(stderr, "Fatal error during initialization: %s\n",
error_message); error_message);
abort(); abort();
@ -4003,6 +4005,7 @@ static mps_res_t obj_scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
break; break;
default: default:
assert(0); assert(0);
fflush(stdout);
fprintf(stderr, "Unexpected object on the heap\n"); fprintf(stderr, "Unexpected object on the heap\n");
abort(); abort();
} }
@ -4073,6 +4076,7 @@ static mps_addr_t obj_skip(mps_addr_t base)
break; break;
default: default:
assert(0); assert(0);
fflush(stdout);
fprintf(stderr, "Unexpected object on the heap\n"); fprintf(stderr, "Unexpected object on the heap\n");
abort(); abort();
} }
@ -4318,7 +4322,7 @@ static int start(int argc, char *argv[])
mps_addr_t ref; mps_addr_t ref;
mps_res_t res; mps_res_t res;
mps_root_t globals_root; mps_root_t globals_root;
int exit_code; int exit_code = EXIT_SUCCESS;
total = (size_t)0; total = (size_t)0;
error_handler = &jb; error_handler = &jb;
@ -4366,21 +4370,23 @@ static int start(int argc, char *argv[])
make_operator(optab[i].name, optab[i].entry, make_operator(optab[i].name, optab[i].entry,
obj_empty, obj_empty, env, op_env)); obj_empty, obj_empty, env, op_env));
} else { } else {
fflush(stdout);
fprintf(stderr, fprintf(stderr,
"Fatal error during initialization: %s\n", "Fatal error during initialization: %s\n",
error_message); error_message);
abort(); abort();
} }
if(argc >= 2) { if (argc > 0) {
/* Non-interactive file execution */ /* Non-interactive file execution */
if(setjmp(*error_handler) != 0) { if(setjmp(*error_handler) != 0) {
fflush(stdout);
fprintf(stderr, "%s\n", error_message); fprintf(stderr, "%s\n", error_message);
fflush(stderr);
exit_code = EXIT_FAILURE; exit_code = EXIT_FAILURE;
} else { } else
load(env, op_env, make_string(strlen(argv[1]), argv[1])); for (i = 0; i < argc; ++i)
exit_code = EXIT_SUCCESS; load(env, op_env, make_string(strlen(argv[i]), argv[i]));
}
} else { } else {
/* Ask the MPS to tell us when it's garbage collecting so that we can /* Ask the MPS to tell us when it's garbage collecting so that we can
print some messages. Completely optional. */ print some messages. Completely optional. */
@ -4394,12 +4400,15 @@ static int start(int argc, char *argv[])
"If you recurse too much the interpreter may crash from using too much C stack."); "If you recurse too much the interpreter may crash from using too much C stack.");
for(;;) { for(;;) {
if(setjmp(*error_handler) != 0) { if(setjmp(*error_handler) != 0) {
fflush(stdout);
fprintf(stderr, "%s\n", error_message); fprintf(stderr, "%s\n", error_message);
fflush(stderr);
} }
mps_chat(); mps_chat();
printf("%lu, %lu> ", (unsigned long)total, printf("%lu, %lu> ", (unsigned long)total,
(unsigned long)mps_collections(arena)); (unsigned long)mps_collections(arena));
fflush(stdout);
obj = read(input); obj = read(input);
if(obj == obj_eof) break; if(obj == obj_eof) break;
obj = eval(env, op_env, obj); obj = eval(env, op_env, obj);
@ -4409,7 +4418,6 @@ static int start(int argc, char *argv[])
} }
} }
puts("Bye."); puts("Bye.");
exit_code = EXIT_SUCCESS;
} }
/* See comment at the end of `main` about cleaning up. */ /* See comment at the end of `main` about cleaning up. */
@ -4442,6 +4450,7 @@ static mps_gen_param_s obj_gen_params[] = {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
size_t arenasize = 32ul * 1024 * 1024;
mps_res_t res; mps_res_t res;
mps_chain_t obj_chain; mps_chain_t obj_chain;
mps_fmt_t obj_fmt, buckets_fmt; mps_fmt_t obj_fmt, buckets_fmt;
@ -4449,11 +4458,41 @@ int main(int argc, char *argv[])
mps_root_t reg_root; mps_root_t reg_root;
int exit_code; int exit_code;
void *marker = &marker; void *marker = &marker;
int ch;
while ((ch = getopt(argc, argv, "m:")) != -1)
switch (ch) {
case 'm': {
char *p;
arenasize = (unsigned)strtoul(optarg, &p, 10);
switch(toupper(*p)) {
case 'G': arenasize <<= 30; break;
case 'M': arenasize <<= 20; break;
case 'K': arenasize <<= 10; break;
case '\0': break;
default:
fprintf(stderr, "Bad arena size %s\n", optarg);
return EXIT_FAILURE;
}
}
break;
default:
fprintf(stderr,
"Usage: %s [option...] [file...]\n"
"Options:\n"
" -m n, --arena-size=n[KMG]?\n"
" Initial size of arena (default %lu).\n",
argv[0],
(unsigned long)arenasize);
return EXIT_FAILURE;
}
argc -= optind;
argv += optind;
/* Create an MPS arena. There is usually only one of these in a process. /* Create an MPS arena. There is usually only one of these in a process.
It holds all the MPS "global" state and is where everything happens. */ It holds all the MPS "global" state and is where everything happens. */
MPS_ARGS_BEGIN(args) { MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 32 * 1024 * 1024); MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arenasize);
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args); } MPS_ARGS_END(args);
if (res != MPS_RES_OK) error("Couldn't create arena"); if (res != MPS_RES_OK) error("Couldn't create arena");

View file

@ -281,6 +281,7 @@ static void error(char *format, ...)
if (error_handler) { if (error_handler) {
longjmp(*error_handler, 1); longjmp(*error_handler, 1);
} else { } else {
fflush(stdout);
fprintf(stderr, "Fatal error during initialization: %s\n", fprintf(stderr, "Fatal error during initialization: %s\n",
error_message); error_message);
abort(); abort();
@ -3599,6 +3600,7 @@ int main(int argc, char *argv[])
make_operator(optab[i].name, optab[i].entry, make_operator(optab[i].name, optab[i].entry,
obj_empty, obj_empty, env, op_env)); obj_empty, obj_empty, env, op_env));
} else { } else {
fflush(stdout);
fprintf(stderr, fprintf(stderr,
"Fatal error during initialization: %s\n", "Fatal error during initialization: %s\n",
error_message); error_message);
@ -3608,18 +3610,24 @@ int main(int argc, char *argv[])
if(argc >= 2) { if(argc >= 2) {
/* Non-interactive file execution */ /* Non-interactive file execution */
if(setjmp(*error_handler) != 0) { if(setjmp(*error_handler) != 0) {
fflush(stdout);
fprintf(stderr, "%s\n", error_message); fprintf(stderr, "%s\n", error_message);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
load(env, op_env, argv[1]); for (i = 1; i < argc; ++i)
load(env, op_env, argv[i]);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} else { } else {
/* Interactive read-eval-print loop */ /* Interactive read-eval-print loop */
puts("Scheme Test Harness"); puts("Scheme Test Harness");
for(;;) { for(;;) {
if(setjmp(*error_handler) != 0) if(setjmp(*error_handler) != 0) {
fflush(stdout);
fprintf(stderr, "%s\n", error_message); fprintf(stderr, "%s\n", error_message);
fflush(stderr);
}
printf("%lu> ", (unsigned long)total); printf("%lu> ", (unsigned long)total);
fflush(stdout);
obj = read(input); obj = read(input);
if(obj == obj_eof) break; if(obj == obj_eof) break;
obj = eval(env, op_env, obj); obj = eval(env, op_env, obj);

Some files were not shown because too many files have changed in this diff Show more