1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Test the failover module (both always and never failing over).

Fix result code bug in failoverInsert.
Test all result codes in fotest.
Tidy up code and documentation.

Copied from Perforce
 Change: 185207
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2014-04-03 14:46:58 +01:00
parent 0b159dc650
commit ce6b34aa8f
11 changed files with 132 additions and 105 deletions

View file

@ -238,7 +238,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
MPS_ARGS_ADD(liArgs, CBSFastFind, TRUE);
MPS_ARGS_ADD(liArgs, CBSZoned, arena->zoned);
MPS_ARGS_DONE(liArgs);
res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena, alignment, arena, liArgs);
res = LandInit(ArenaFreeLand(arena), CBSLandClassGet(), arena,
alignment, arena, liArgs);
} MPS_ARGS_END(liArgs);
AVER(res == ResOK); /* no allocation, no failure expected */
if (res != ResOK)
@ -310,9 +311,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
that describes the free address space in the primary chunk. */
arena->hasFreeLand = TRUE;
res = ArenaFreeLandInsert(arena,
PageIndexBase(arena->primary,
arena->primary->allocBase),
arena->primary->limit);
PageIndexBase(arena->primary,
arena->primary->allocBase),
arena->primary->limit);
if (res != ResOK)
goto failPrimaryLand;
@ -704,10 +705,10 @@ static void arenaExcludePage(Arena arena, Range pageRange)
}
/* arenaLandInsert -- add a block to an arena Land, extending pool if necessary
/* arenaLandInsert -- add range to arena's land, maybe extending block pool
*
* The arena's Land can't get memory in the usual way because they are used
* in the basic allocator, so we allocate pages specially.
* The arena's land can't get memory in the usual way because it is
* used in the basic allocator, so we allocate pages specially.
*
* Only fails if it can't get a page for the block pool.
*/
@ -722,7 +723,7 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
if (res == ResLIMIT) { /* freeLand MFS pool ran out of blocks */
if (res == ResLIMIT) { /* CBS block pool ran out of blocks */
RangeStruct pageRange;
res = arenaExtendCBSBlockPool(&pageRange, arena);
if (res != ResOK)
@ -730,7 +731,7 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
/* .insert.exclude: Must insert before exclude so that we can
bootstrap when the zoned CBS is empty. */
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
AVER(res == ResOK); /* we just gave memory to the Land */
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
arenaExcludePage(arena, &pageRange);
}
@ -738,11 +739,11 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
}
/* ArenaFreeLandInsert -- add a block to arena Land, maybe stealing memory
/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory
*
* See arenaLandInsert. This function may only be applied to mapped pages
* and may steal them to store Land nodes if it's unable to allocate
* space for CBS nodes.
* See arenaLandInsert. This function may only be applied to mapped
* pages and may steal them to store Land nodes if it's unable to
* allocate space for CBS blocks.
*
* IMPORTANT: May update rangeIO.
*/
@ -777,14 +778,14 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
/* Try again. */
res = LandInsert(rangeReturn, ArenaFreeLand(arena), rangeIO);
AVER(res == ResOK); /* we just gave memory to the Land */
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
}
AVER(res == ResOK); /* not expecting other kinds of error from the Land */
}
/* ArenaFreeLandInsert -- add block to free Land, extending pool if necessary
/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool
*
* The inserted block of address space may not abut any existing block.
* This restriction ensures that we don't coalesce chunks and allocate
@ -812,7 +813,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
}
/* ArenaFreeLandDelete -- remove a block from free Land, extending pool if necessary
/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool
*
* This is called from ChunkFinish in order to remove address space from
* the arena.

View file

@ -26,6 +26,7 @@ SRCID(cbs, "$Id$");
#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit)
#define cbsLand(cbs) (&((cbs)->landStruct))
#define cbsOfLand(land) PARENT(CBSStruct, landStruct, land)
#define cbsSplay(cbs) (&((cbs)->splayTreeStruct))
#define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay)
@ -66,7 +67,7 @@ Bool CBSCheck(CBS cbs)
{
/* See .enter-leave.simple. */
CHECKS(CBS, cbs);
CHECKD(Land, &cbs->landStruct);
CHECKD(Land, cbsLand(cbs));
CHECKD(SplayTree, cbsSplay(cbs));
/* nothing to check about treeSize */
CHECKD(Pool, cbs->blockPool);
@ -211,7 +212,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree)
cbsUpdateNode(splay, tree);
block = cbsBlockOfTree(tree);
arena = cbsOfSplay(splay)->landStruct.arena;
arena = LandArena(cbsLand(cbsOfSplay(splay)));
zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block));
if (TreeHasLeft(tree))
@ -740,7 +741,7 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS)
cbsBlock = cbsBlockOfTree(tree);
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
cont = (*closure->visitor)(&delete, land, &range, closure->closureP, closure->closureS);
AVER(!delete);
AVER(!delete); /* <design/cbs/#limit.iterate> */
if (!cont)
return FALSE;
METER_ACC(cbs->treeSearch, cbs->treeSize);
@ -1101,6 +1102,8 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream)
" blockPool: $P\n", (WriteFP)cbsBlockPool(cbs),
" fastFind: $U\n", (WriteFU)cbs->fastFind,
" inCBS: $U\n", (WriteFU)cbs->inCBS,
" ownPool: $U\n", (WriteFU)cbs->ownPool,
" zoned: $U\n", (WriteFU)cbs->zoned,
" treeSize: $U\n", (WriteFU)cbs->treeSize,
NULL);
if (res != ResOK) return res;

View file

@ -87,10 +87,8 @@ static Res failoverInsert(Range rangeReturn, Land land, Range range)
LandFlush(fo->primary, fo->secondary);
res = LandInsert(rangeReturn, fo->primary, range);
if (ResIsAllocFailure(res)) {
/* primary ran out of memory: try secondary instead. */
if (res != ResOK && res != ResFAIL)
res = LandInsert(rangeReturn, fo->secondary, range);
}
return res;
}
@ -118,11 +116,11 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range)
if (res == ResFAIL) {
/* Range not found in primary: try secondary. */
return LandDelete(rangeReturn, fo->secondary, range);
} else if (ResIsAllocFailure(res)) {
/* Range was found in primary, but couldn't be deleted because the
* primary is out of memory. Delete the whole of oldRange, and
* re-insert the fragments (which might end up in the secondary).
* See <design/failover/#impl.assume.delete>.
} else if (res != ResOK) {
/* Range was found in primary, but couldn't be deleted, perhaps
* because the primary is out of memory. Delete the whole of
* oldRange, and re-insert the fragments (which might end up in
* the secondary). See <design/failover/#impl.assume.delete>.
*/
res = LandDelete(&dummyRange, fo->primary, &oldRange);
if (res != ResOK)

View file

@ -38,28 +38,37 @@
/* Accessors for the CBS used to implement a pool. */
extern Land _mps_mvff_cbs(mps_pool_t);
extern Land _mps_mvt_cbs(mps_pool_t);
extern Land _mps_mvff_cbs(Pool);
extern Land _mps_mvt_cbs(Pool);
/* "OOM" pool class -- dummy alloc/free pool class whose alloc()
* method always returns ResMEMORY */
* method always fails. */
static Res OOMAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res oomAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
{
UNUSED(pReturn);
UNUSED(pool);
UNUSED(size);
UNUSED(withReservoirPermit);
return ResMEMORY;
switch (rnd() % 4) {
case 0:
return ResRESOURCE;
case 1:
return ResMEMORY;
case 2:
return ResLIMIT;
default:
return ResCOMMIT_LIMIT;
}
}
extern PoolClass PoolClassOOM(void);
extern PoolClass OOMPoolClassGet(void);
DEFINE_POOL_CLASS(OOMPoolClass, this)
{
INHERIT_CLASS(this, AbstractAllocFreePoolClass);
this->alloc = OOMAlloc;
this->alloc = oomAlloc;
}
@ -81,16 +90,17 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
/* set_oom -- set blockPool of CBS to OOM or MFS according to argument. */
static void set_oom(CBS cbs, int oom)
static void set_oom(Land land, int oom)
{
cbs->blockPool->class = oom ? EnsureOOMPoolClass() : PoolClassMFS();
CBS cbs = PARENT(CBSStruct, landStruct, land);
cbs->blockPool->class = oom ? OOMPoolClassGet() : PoolClassMFS();
}
/* stress -- create an allocation point and allocate in it */
static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t),
mps_align_t alignment, mps_pool_t pool, CBS cbs)
mps_align_t alignment, mps_pool_t pool, Land cbs)
{
mps_res_t res = MPS_RES_OK;
mps_ap_t ap;
@ -180,8 +190,8 @@ int main(int argc, char *argv[])
die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF");
} MPS_ARGS_END(args);
{
CBS cbs = (CBS)_mps_mvff_cbs(pool);
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVFF");
die(stress(randomSizeAligned, alignment, pool, _mps_mvff_cbs(pool)),
"stress MVFF");
}
mps_pool_destroy(pool);
mps_arena_destroy(arena);
@ -199,8 +209,8 @@ int main(int argc, char *argv[])
die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF");
} MPS_ARGS_END(args);
{
CBS cbs = (CBS)_mps_mvt_cbs(pool);
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVT");
die(stress(randomSizeAligned, alignment, pool, _mps_mvt_cbs(pool)),
"stress MVT");
}
mps_pool_destroy(pool);
mps_arena_destroy(arena);

View file

@ -3,7 +3,7 @@
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* The MPS contains two land implementations:
* The MPS contains three land implementations:
*
* 1. the CBS (Coalescing Block Structure) module maintains blocks in
* a splay tree for fast access with a cost in storage;
@ -11,6 +11,9 @@
* 2. the Freelist module maintains blocks in an address-ordered
* singly linked list for zero storage overhead with a cost in
* performance.
*
* 3. the Failover module implements a mechanism for using CBS until
* it fails, then falling back to a Freelist.
*/
#include "cbs.h"
@ -20,6 +23,7 @@
#include "mps.h"
#include "mpsavm.h"
#include "mpstd.h"
#include "poolmfs.h"
#include "testlib.h"
#include <stdarg.h>
@ -479,13 +483,16 @@ extern int main(int argc, char *argv[])
void *p;
Addr dummyBlock;
BT allocTable;
MFSStruct blockPool;
CBSStruct cbsStruct;
FreelistStruct flStruct;
FailoverStruct foStruct;
Land cbs = &cbsStruct.landStruct;
Land fl = &flStruct.landStruct;
Land fo = &foStruct.landStruct;
Pool mfs = &blockPool.poolStruct;
Align align;
int i;
testlib_init(argc, argv);
align = (1 << rnd() % 4) * MPS_PF_ALIGN;
@ -512,6 +519,8 @@ extern int main(int argc, char *argv[])
(char *)dummyBlock + ArraySize);
}
/* 1. Test CBS */
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, CBSFastFind, TRUE);
die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL, args),
@ -524,6 +533,8 @@ extern int main(int argc, char *argv[])
test(&state, nCBSOperations);
LandFinish(cbs);
/* 2. Test Freelist */
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
mps_args_none),
"failed to initialise Freelist");
@ -531,27 +542,46 @@ extern int main(int argc, char *argv[])
test(&state, nFLOperations);
LandFinish(fl);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, CBSFastFind, TRUE);
die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align,
NULL, args),
"failed to initialise CBS");
} MPS_ARGS_END(args);
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
mps_args_none),
"failed to initialise Freelist");
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, FailoverPrimary, cbs);
MPS_ARGS_ADD(args, FailoverSecondary, fl);
die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL,
args),
"failed to initialise Failover");
} MPS_ARGS_END(args);
state.land = fo;
test(&state, nFOOperations);
LandFinish(fo);
LandFinish(fl);
LandFinish(cbs);
/* 3. Test CBS-failing-over-to-Freelist (always failing over on
* first iteration, never failing over on second; see fotest.c for a
* test case that randomly switches fail-over on and off)
*/
for (i = 0; i < 2; ++i) {
MPS_ARGS_BEGIN(piArgs) {
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct));
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaAlign(arena));
MPS_ARGS_ADD(piArgs, MFSExtendSelf, i);
MPS_ARGS_DONE(piArgs);
die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit");
} MPS_ARGS_END(piArgs);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, CBSFastFind, TRUE);
MPS_ARGS_ADD(args, CBSBlockPool, mfs);
die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL,
args),
"failed to initialise CBS");
} MPS_ARGS_END(args);
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
mps_args_none),
"failed to initialise Freelist");
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, FailoverPrimary, cbs);
MPS_ARGS_ADD(args, FailoverSecondary, fl);
die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL,
args),
"failed to initialise Failover");
} MPS_ARGS_END(args);
state.land = fo;
test(&state, nFOOperations);
LandFinish(fo);
LandFinish(fl);
LandFinish(cbs);
PoolFinish(mfs);
}
mps_arena_destroy(arena);

View file

@ -701,8 +701,8 @@ typedef union FreelistBlockUnion *FreelistBlock;
typedef struct FreelistStruct {
LandStruct landStruct; /* superclass fields come first */
FreelistBlock list;
Count listSize;
FreelistBlock list; /* first block in list or NULL if empty */
Count listSize; /* number of blocks in list */
Sig sig; /* .class.end-sig */
} FreelistStruct;

View file

@ -385,9 +385,7 @@ static Bool MVTCheck(MVT mvt)
CHECKD(Pool, &mvt->poolStruct);
CHECKL(mvt->poolStruct.class == MVTPoolClassGet());
CHECKD(CBS, &mvt->cbsStruct);
/* CHECKL(CBSCheck(MVTCBS(mvt))); */
CHECKD(ABQ, &mvt->abqStruct);
/* CHECKL(ABQCheck(MVTABQ(mvt))); */
CHECKD(Freelist, &mvt->flStruct);
CHECKD(Failover, &mvt->foStruct);
CHECKL(mvt->reuseSize >= 2 * mvt->fillSize);
@ -402,8 +400,7 @@ static Bool MVTCheck(MVT mvt)
if (mvt->splinter) {
CHECKL(AddrOffset(mvt->splinterBase, mvt->splinterLimit) >=
mvt->minSize);
/* CHECKD(Seg, mvt->splinterSeg); */
CHECKL(SegCheck(mvt->splinterSeg));
CHECKD(Seg, mvt->splinterSeg);
CHECKL(mvt->splinterBase >= SegBase(mvt->splinterSeg));
CHECKL(mvt->splinterLimit <= SegLimit(mvt->splinterSeg));
}
@ -1257,6 +1254,10 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena)
}
/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is
* empty.
*/
static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range,
void *closureP, Size closureS)
{
@ -1275,9 +1276,6 @@ static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range,
return MVTReserve(mvt, range);
}
/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is
* empty.
*/
static void MVTRefillABQIfEmpty(MVT mvt, Size size)
{
AVERT(MVT, mvt);
@ -1296,10 +1294,9 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size)
}
/* Closure for MVTContingencySearch */
typedef struct MVTContigencyStruct *MVTContigency;
/* MVTContingencySearch -- search free lists for a block of a given size */
typedef struct MVTContigencyStruct
typedef struct MVTContigencyClosureStruct
{
MVT mvt;
Bool found;
@ -1309,12 +1306,7 @@ typedef struct MVTContigencyStruct
/* meters */
Count steps;
Count hardSteps;
} MVTContigencyStruct;
/* MVTContingencyVisitor -- called from LandIterate at the behest of
* MVTContingencySearch.
*/
} MVTContigencyClosureStruct, *MVTContigencyClosure;
static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range,
void *closureP, Size closureS)
@ -1322,7 +1314,7 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range,
MVT mvt;
Size size;
Addr base, limit;
MVTContigency cl;
MVTContigencyClosure cl;
AVER(deleteReturn != NULL);
AVERT(Land, land);
@ -1360,14 +1352,10 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range,
return TRUE;
}
/* MVTContingencySearch -- search the free lists for a block of size
* min.
*/
static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
MVT mvt, Size min)
{
MVTContigencyStruct cls;
MVTContigencyClosureStruct cls;
cls.mvt = mvt;
cls.found = FALSE;
@ -1394,6 +1382,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
/* MVTCheckFit -- verify that segment-aligned block of size min can
* fit in a candidate address range.
*/
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
{
Seg seg;
@ -1423,12 +1412,10 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
/* Return the CBS of an MVT pool for the benefit of fotest.c. */
extern Land _mps_mvt_cbs(mps_pool_t);
Land _mps_mvt_cbs(mps_pool_t mps_pool) {
Pool pool;
extern Land _mps_mvt_cbs(Pool);
Land _mps_mvt_cbs(Pool pool) {
MVT mvt;
pool = (Pool)mps_pool;
AVERT(Pool, pool);
mvt = Pool2MVT(pool);
AVERT(MVT, mvt);

View file

@ -748,12 +748,10 @@ static Bool MVFFCheck(MVFF mvff)
/* Return the CBS of an MVFF pool for the benefit of fotest.c. */
extern Land _mps_mvff_cbs(mps_pool_t);
Land _mps_mvff_cbs(mps_pool_t mps_pool) {
Pool pool;
extern Land _mps_mvff_cbs(Pool);
Land _mps_mvff_cbs(Pool pool) {
MVFF mvff;
pool = (Pool)mps_pool;
AVERT(Pool, pool);
mvff = Pool2MVFF(pool);
AVERT(MVFF, mvff);

View file

@ -232,7 +232,7 @@ Document History
----------------
- 1998-05-01 Gavin Matthews. This document was derived from the
outline in design.mps.poolmvt_.
outline in design.mps.poolmv2(2).
- 1998-07-22 Gavin Matthews. Updated in response to approval comments
in change.epcore.anchovy.160040. There is too much fragmentation in

View file

@ -151,8 +151,8 @@ exceed the recorded size of the list.
_`.improve.maxsize`: We could maintain the maximum size of any range
on the list, and use that to make an early exit from
``LandFindLargest()``. It's not clear that this would actually be an
improvement.
``freelistFindLargest()``. It's not clear that this would actually be
an improvement.

View file

@ -68,15 +68,15 @@ message_ MPS to client message protocol
message-gc_ Messages sent when garbage collection begins or ends
object-debug_ Debugging Features for Client Objects
pool_ The design of the pool and pool class mechanisms
poolamc_ The design of the automatic mostly-copying memory pool class
poolams_ The design of the automatic mark-and-sweep pool class
poolawl_ Automatic weak linked
poollo_ Leaf object pool class
poolamc_ Automatic Mostly-Copying pool class
poolams_ Automatic Mark-and-Sweep pool class
poolawl_ Automatic Weak Linked pool class
poollo_ Leaf Object pool class
poolmfs_ Manual Fixed Small pool class
poolmrg_ Guardian poolclass
poolmrg_ Manual Rank Guardian pool class
poolmv_ Manual Variable pool class
poolmvt_ Manual Variable Temporal pool class
poolmvff_ Manually Variable First-Fit pool
poolmvff_ Manual Variable First-Fit pool class
prot_ Generic design of the protection module
protan_ ANSI implementation of protection module
protli_ Linux implementation of protection module