1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-23 23:36:27 -07:00

Merge branch/2014-04-08/align into branch/2014-05-15/size.

Copied from Perforce
 Change: 186116
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2014-05-15 14:54:36 +01:00
commit 7e22bed98f
26 changed files with 599 additions and 326 deletions

View file

@ -105,7 +105,7 @@ static mps_addr_t make(void)
/* test -- the actual stress test */
static mps_pool_debug_option_s freecheckOptions =
{ NULL, 0, (const void *)"Dead", 4 };
{ NULL, 0, (void *)"Dead", 4 };
static void test_pool(mps_class_t pool_class, mps_arg_s args[],
mps_bool_t haveAmbiguous)

View file

@ -43,28 +43,25 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
/* stress -- create a pool of the requested type and allocate in it */
static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
mps_arena_t arena, ...)
static mps_res_t stress(mps_arena_t arena, 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[])
{
mps_res_t res = MPS_RES_OK;
mps_pool_t pool;
mps_ap_t ap;
va_list arg;
size_t i, k;
int *ps[testSetSIZE];
size_t ss[testSetSIZE];
va_start(arg, arena);
res = mps_pool_create_v(&pool, arena, class, arg);
va_end(arg);
if (res != MPS_RES_OK)
return res;
printf("stress %s\n", name);
die(mps_pool_create_k(&pool, arena, class, args), "pool_create");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
/* allocate a load of objects */
for (i=0; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
ss[i] = (*size)(i, align);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK)
@ -96,7 +93,7 @@ static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
}
/* allocate some new objects */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
ss[i] = (*size)(i, align);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
@ -111,63 +108,72 @@ allocFail:
}
/* randomSizeAligned -- produce sizes both large and small,
* aligned by platform alignment */
/* randomSizeAligned -- produce sizes both large and small, aligned to
* align.
*/
static size_t randomSizeAligned(size_t i)
static size_t randomSizeAligned(size_t i, mps_align_t align)
{
size_t maxSize = 2 * 160 * 0x2000;
/* Reduce by a factor of 2 every 10 cycles. Total allocation about 40 MB. */
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, MPS_PF_ALIGN);
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, align);
}
static mps_pool_debug_option_s bothOptions = {
/* .fence_template = */ (const void *)"postpostpostpost",
/* .fence_size = */ MPS_PF_ALIGN,
/* .free_template = */ (const void *)"DEAD",
/* .fence_template = */ (void *)"post",
/* .fence_size = */ 4,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s fenceOptions = {
/* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0",
/* .fence_size = */ 16,
/* .fence_template = */ (void *)"123456789abcdef",
/* .fence_size = */ 15,
/* .free_template = */ NULL,
/* .free_size = */ 0
};
/* testInArena -- test all the pool classes in the given arena */
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
{
mps_res_t res;
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
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_FIRST_FIT, TRUE);
die(stress(arena, align, randomSizeAligned, "MVFF", mps_class_mvff(), args),
"stress MVFF");
} MPS_ARGS_END(args);
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */
/* yet (MV Debug works here, because it fakes it through PoolAlloc). */
printf("MVFF\n");
res = stress(mps_class_mvff(), randomSizeAligned, arena,
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MVFF");
printf("MV debug\n");
res = stress(mps_class_mv_debug(), randomSizeAligned, arena,
options, (size_t)65536, (size_t)32, (size_t)65536);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MV debug");
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, align, randomSizeAligned, "MV", mps_class_mv(), args),
"stress MV");
} MPS_ARGS_END(args);
printf("MV\n");
res = stress(mps_class_mv(), randomSizeAligned, arena,
(size_t)65536, (size_t)32, (size_t)65536);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MV");
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, align, randomSizeAligned, "MV debug",
mps_class_mv_debug(), args),
"stress MV debug");
} MPS_ARGS_END(args);
printf("MVT\n");
res = stress(mps_class_mvt(), randomSizeAligned, arena,
(size_t)8, (size_t)32, (size_t)65536, (mps_word_t)4,
(mps_word_t)50);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MVT");
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, align, randomSizeAligned, "MVT", mps_class_mvt(), args),
"stress MVT");
} MPS_ARGS_END(args);
}

View file

@ -354,6 +354,7 @@
/* Pool MV Configuration -- see <code/poolmv.c> */
#define MV_ALIGN_DEFAULT MPS_PF_ALIGN
#define MV_EXTEND_BY_DEFAULT ((Size)65536)
#define MV_AVG_SIZE_DEFAULT ((Size)32)
#define MV_MAX_SIZE_DEFAULT ((Size)65536)

View file

@ -123,10 +123,17 @@ Bool PoolDebugOptionsCheck(PoolDebugOptions opt)
ARG_DEFINE_KEY(pool_debug_options, PoolDebugOptions);
static char debugFencepostTemplate[4] = {'P', 'O', 'S', 'T'};
static char debugFreeTemplate[4] = {'D', 'E', 'A', 'D'};
static PoolDebugOptionsStruct debugPoolOptionsDefault = {
debugFencepostTemplate, 4, debugFreeTemplate, 4,
};
static Res DebugPoolInit(Pool pool, ArgList args)
{
Res res;
PoolDebugOptions options;
PoolDebugOptions options = &debugPoolOptionsDefault;
PoolDebugMixin debug;
TagInitMethod tagInit;
Size tagSize;
@ -134,10 +141,8 @@ static Res DebugPoolInit(Pool pool, ArgList args)
AVERT(Pool, pool);
/* TODO: Split this structure into separate keyword arguments,
now that we can support them. */
ArgRequire(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS);
options = (PoolDebugOptions)arg.val.pool_debug_options;
if (ArgPick(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS))
options = (PoolDebugOptions)arg.val.pool_debug_options;
AVERT(PoolDebugOptions, options);
@ -158,10 +163,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
/* into Addr memory, to avoid breaking <design/type/#addr.use>. */
debug->fenceSize = options->fenceSize;
if (debug->fenceSize != 0) {
if (debug->fenceSize % PoolAlignment(pool) != 0) {
res = ResPARAM;
goto alignFail;
}
/* Fenceposting turns on tagging */
if (tagInit == NULL) {
tagSize = 0;
@ -176,10 +177,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
/* into Addr memory, to avoid breaking <design/type#addr.use>. */
debug->freeSize = options->freeSize;
if (debug->freeSize != 0) {
if (PoolAlignment(pool) % debug->freeSize != 0) {
res = ResPARAM;
goto alignFail;
}
debug->freeTemplate = options->freeTemplate;
}
@ -205,7 +202,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
return ResOK;
tagFail:
alignFail:
SuperclassOfPool(pool)->finish(pool);
AVER(res != ResOK);
return res;
@ -231,38 +227,119 @@ static void DebugPoolFinish(Pool pool)
}
/* freeSplat -- splat free block with splat pattern
/* patternCopy -- copy pattern to fill a range
*
* If base is in a segment, the whole block has to be in it.
* Fill the range of addresses from base (inclusive) to limit
* (exclusive) with copies of pattern (which is size bytes long).
*
* Keep in sync with patternCheck.
*/
static void patternCopy(Addr pattern, Size size, Addr base, Addr limit)
{
Addr p;
AVER(pattern != NULL);
AVER(0 < size);
AVER(base != NULL);
AVER(base <= limit);
p = base;
while (p < limit) {
Addr end = AddrAdd(p, size);
Addr rounded = AddrRoundUp(p, size);
Size offset = (Word)p % size;
if (end < p || rounded < p) {
/* Address range overflow */
break;
} else if (p == rounded && end <= limit) {
/* Room for a whole copy */
(void)AddrCopy(p, pattern, size);
p = end;
} else if (p < rounded && rounded <= end && rounded <= limit) {
/* Copy up to rounded */
(void)AddrCopy(p, (char *)pattern + offset, AddrOffset(p, rounded));
p = rounded;
} else {
/* Copy up to limit */
AVER(limit <= end && (p == rounded || limit <= rounded));
(void)AddrCopy(p, (char *)pattern + offset, AddrOffset(p, limit));
p = limit;
}
}
}
/* patternCheck -- check pattern against a range
*
* Compare the range of addresses from base (inclusive) to limit
* (exclusive) with copies of pattern (which is size bytes long). The
* copies of pattern must be arranged so that fresh copies start at
* aligned addresses wherever possible.
*
* Keep in sync with patternCopy.
*/
static Bool patternCheck(Addr pattern, Size size, Addr base, Addr limit)
{
Addr p;
AVER(pattern != NULL);
AVER(0 < size);
AVER(base != NULL);
AVER(base <= limit);
p = base;
while (p < limit) {
Addr end = AddrAdd(p, size);
Addr rounded = AddrRoundUp(p, size);
Size offset = (Word)p % size;
if (end < p || rounded < p) {
/* Address range overflow */
break;
} else if (p == rounded && end <= limit) {
/* Room for a whole copy */
if (AddrComp(p, pattern, size) != 0)
return FALSE;
p = end;
} else if (p < rounded && rounded <= end && rounded <= limit) {
/* Copy up to rounded */
if (AddrComp(p, (char *)pattern + offset, AddrOffset(p, rounded)) != 0)
return FALSE;
p = rounded;
} else {
/* Copy up to limit */
AVER(limit <= end && (p == rounded || limit <= rounded));
if (AddrComp(p, (char *)pattern + offset, AddrOffset(p, limit)) != 0)
return FALSE;
p = limit;
}
}
return TRUE;
}
/* freeSplat -- splat free block with splat pattern */
static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
{
Addr p, next;
Size freeSize = debug->freeSize;
Arena arena;
Seg seg = NULL; /* suppress "may be used uninitialized" */
Bool inSeg;
Seg seg;
AVER(base < limit);
/* If the block is in a segment, make sure any shield is up. */
arena = PoolArena(pool);
inSeg = SegOfAddr(&seg, arena, base);
if (inSeg) {
AVER(limit <= SegLimit(seg));
ShieldExpose(arena, seg);
if (SegOfAddr(&seg, arena, base)) {
do {
ShieldExpose(arena, seg);
} while (SegLimit(seg) < limit && SegNext(&seg, arena, seg));
}
/* Write as many copies of the template as fit in the block. */
for (p = base, next = AddrAdd(p, freeSize);
next <= limit && p < next /* watch out for overflow in next */;
p = next, next = AddrAdd(next, freeSize))
(void)AddrCopy(p, debug->freeTemplate, freeSize);
/* Fill the tail of the block with a partial copy of the template. */
if (next > limit || next < p)
(void)AddrCopy(p, debug->freeTemplate, AddrOffset(p, limit));
if (inSeg) {
ShieldCover(arena, seg);
patternCopy(debug->freeTemplate, debug->freeSize, base, limit);
if (SegOfAddr(&seg, arena, base)) {
do {
ShieldCover(arena, seg);
} while (SegLimit(seg) < limit && SegNext(&seg, arena, seg));
}
}
@ -271,40 +348,24 @@ static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
{
Addr p, next;
Size freeSize = debug->freeSize;
Res res;
Bool res;
Arena arena;
Seg seg = NULL; /* suppress "may be used uninitialized" */
Bool inSeg;
Seg seg;
AVER(base < limit);
/* If the block is in a segment, make sure any shield is up. */
arena = PoolArena(pool);
inSeg = SegOfAddr(&seg, arena, base);
if (inSeg) {
AVER(limit <= SegLimit(seg));
ShieldExpose(arena, seg);
if (SegOfAddr(&seg, arena, base)) {
do {
ShieldExpose(arena, seg);
} while (SegLimit(seg) < limit && SegNext(&seg, arena, seg));
}
/* Compare this to the AddrCopys in freeSplat. */
/* Check the complete copies of the template in the block. */
for (p = base, next = AddrAdd(p, freeSize);
next <= limit && p < next /* watch out for overflow in next */;
p = next, next = AddrAdd(next, freeSize))
if (AddrComp(p, debug->freeTemplate, freeSize) != 0) {
res = FALSE; goto done;
}
/* Check the partial copy of the template at the tail of the block. */
if (next > limit || next < p)
if (AddrComp(p, debug->freeTemplate, AddrOffset(p, limit)) != 0) {
res = FALSE; goto done;
}
res = TRUE;
done:
if (inSeg) {
ShieldCover(arena, seg);
res = patternCheck(debug->freeTemplate, debug->freeSize, base, limit);
if (SegOfAddr(&seg, arena, base)) {
do {
ShieldCover(arena, seg);
} while (SegLimit(seg) < limit && SegNext(&seg, arena, seg));
}
return res;
}
@ -351,63 +412,75 @@ static void freeCheckFree(PoolDebugMixin debug,
* start fp client object slop end fp
*
* slop is the extra allocation from rounding up the client request to
* the pool's alignment. The fenceposting code does this, so there's a
* better chance of the end fencepost being flush with the next object
* (can't be guaranteed, since the underlying pool could have allocated
* an even larger block). The alignment slop is filled from the
* fencepost template as well (as much as fits, .fence.size guarantees
* the template is larger).
* the pool's alignment. The fenceposting code adds this slop so that
* there's a better chance of the end fencepost being flush with the
* next object (though it can't be guaranteed, since the underlying
* pool could have allocated an even larger block). The alignment slop
* is filled from the fencepost template as well.
*
* Keep in sync with fenceCheck.
*/
static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
Size size, Bool withReservoir)
{
Res res;
Addr new, clientNew;
Size alignedSize;
Addr obj, startFence, clientNew, clientLimit, limit;
Size alignedFenceSize, alignedSize;
AVER(aReturn != NULL);
AVERT(PoolDebugMixin, debug);
AVERT(Pool, pool);
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
res = freeCheckAlloc(&new, debug, pool, alignedSize + 2*debug->fenceSize,
res = freeCheckAlloc(&obj, debug, pool,
alignedSize + 2 * alignedFenceSize,
withReservoir);
if (res != ResOK)
return res;
clientNew = AddrAdd(new, debug->fenceSize);
startFence = obj;
clientNew = AddrAdd(startFence, alignedFenceSize);
clientLimit = AddrAdd(clientNew, size);
limit = AddrAdd(clientNew, alignedSize + alignedFenceSize);
/* @@@@ shields? */
/* start fencepost */
(void)AddrCopy(new, debug->fenceTemplate, debug->fenceSize);
/* alignment slop */
(void)AddrCopy(AddrAdd(clientNew, size),
debug->fenceTemplate, alignedSize - size);
/* end fencepost */
(void)AddrCopy(AddrAdd(clientNew, alignedSize),
debug->fenceTemplate, debug->fenceSize);
patternCopy(debug->fenceTemplate, debug->fenceSize, startFence, clientNew);
patternCopy(debug->fenceTemplate, debug->fenceSize, clientLimit, limit);
*aReturn = clientNew;
return res;
return ResOK;
}
/* fenceCheck -- check fences of an object */
/* fenceCheck -- check fences of an object
*
* Keep in sync with fenceAlloc.
*/
static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size)
{
Size alignedSize;
Addr startFence, clientNew, clientLimit, limit;
Size alignedFenceSize, alignedSize;
AVERT_CRITICAL(PoolDebugMixin, debug);
AVERT_CRITICAL(Pool, pool);
/* Can't check obj */
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
startFence = AddrSub(obj, alignedFenceSize);
clientNew = obj;
clientLimit = AddrAdd(clientNew, size);
limit = AddrAdd(clientNew, alignedSize + alignedFenceSize);
/* @@@@ shields? */
/* Compare this to the AddrCopys in fenceAlloc */
return (AddrComp(AddrSub(obj, debug->fenceSize), debug->fenceTemplate,
debug->fenceSize) == 0
&& AddrComp(AddrAdd(obj, size), debug->fenceTemplate,
alignedSize - size) == 0
&& AddrComp(AddrAdd(obj, alignedSize), debug->fenceTemplate,
debug->fenceSize) == 0);
return patternCheck(debug->fenceTemplate, debug->fenceSize,
startFence, clientNew)
&& patternCheck(debug->fenceTemplate, debug->fenceSize,
clientLimit, limit);
}
@ -416,13 +489,14 @@ static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size)
static void fenceFree(PoolDebugMixin debug,
Pool pool, Addr old, Size size)
{
Size alignedSize;
Size alignedFenceSize, alignedSize;
ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free");
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
freeCheckFree(debug, pool, AddrSub(old, debug->fenceSize),
alignedSize + 2*debug->fenceSize);
freeCheckFree(debug, pool, AddrSub(old, alignedFenceSize),
alignedSize + 2 * alignedFenceSize);
}

View file

@ -1,7 +1,7 @@
/* freelist.h: FREE LIST ALLOCATOR INTERFACE
*
* $Id$
* Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license.
*
* .source: <design/freelist/>.
*/
@ -13,6 +13,8 @@
typedef struct FreelistStruct *Freelist;
#define FreelistMinimumAlignment ((Align)sizeof(FreelistBlock))
extern Bool FreelistCheck(Freelist freelist);
extern LandClass FreelistLandClassGet(void);
@ -22,7 +24,7 @@ extern LandClass FreelistLandClassGet(void);
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2013-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -25,8 +25,7 @@ CFLAGSCOMPILER := \
-Wshadow \
-Wstrict-aliasing=2 \
-Wstrict-prototypes \
-Wswitch-default \
-Wwrite-strings
-Wswitch-default
CFLAGSCOMPILERSTRICT := -ansi -pedantic
# A different set of compiler flags for less strict compilation, for

View file

@ -87,6 +87,7 @@ extern Addr (AddrAlignDown)(Addr addr, Align align);
#define AddrIsAligned(p, a) WordIsAligned((Word)(p), a)
#define AddrAlignUp(p, a) ((Addr)WordAlignUp((Word)(p), a))
#define AddrRoundUp(p, r) ((Addr)WordRoundUp((Word)(p), r))
#define SizeIsAligned(s, a) WordIsAligned((Word)(s), a)
#define SizeAlignUp(s, a) ((Size)WordAlignUp((Word)(s), a))

View file

@ -25,19 +25,19 @@
/* stress -- create a pool of the requested type and allocate in it */
static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
mps_arena_t arena, ...)
static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i),
const char *name, mps_class_t pool_class,
mps_arg_s *args)
{
mps_res_t res;
mps_pool_t pool;
va_list arg;
size_t i, k;
int *ps[testSetSIZE];
size_t ss[testSetSIZE];
va_start(arg, arena);
res = mps_pool_create_v(&pool, arena, class, arg);
va_end(arg);
printf("%s\n", name);
res = mps_pool_create_k(&pool, arena, pool_class, args);
if (res != MPS_RES_OK)
return res;
@ -87,7 +87,7 @@ static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
}
/* randomSize -- produce sizes both latge and small */
/* randomSize -- produce sizes both large and small */
static size_t randomSize(size_t i)
{
@ -99,7 +99,7 @@ static size_t randomSize(size_t i)
}
/* randomSize8 -- produce sizes both latge and small, 8-byte aligned */
/* randomSize8 -- produce sizes both large and small, 8-byte aligned */
static size_t randomSize8(size_t i)
{
@ -121,61 +121,90 @@ static size_t fixedSize(size_t i)
static mps_pool_debug_option_s bothOptions = {
/* .fence_template = */ (const void *)"postpostpostpost",
/* .fence_size = */ MPS_PF_ALIGN,
/* .free_template = */ (const void *)"DEAD",
/* .fence_template = */ (void *)"post",
/* .fence_size = */ 4,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s fenceOptions = {
/* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0",
/* .fence_size = */ 16,
/* .fence_template = */ (void *)"123456789abcdef",
/* .fence_size = */ 15,
/* .free_template = */ NULL,
/* .free_size = */ 0
};
/* testInArena -- test all the pool classes in the given arena */
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
mps_pool_debug_option_s *options)
{
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging */
/* cross-segment allocation (possibly MVFF ought not to). */
printf("MVFF\n");
die(stress(mps_class_mvff(), randomSize8, arena,
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE),
"stress MVFF");
printf("MV debug\n");
die(stress(mps_class_mv_debug(), randomSize, arena,
options, (size_t)65536, (size_t)32, (size_t)65536),
"stress MV debug");
mps_arena_t arena;
printf("MFS\n");
fixedSizeSize = 13;
die(stress(mps_class_mfs(), fixedSize, arena, (size_t)100000, fixedSizeSize),
die(mps_arena_create_k(&arena, arena_class, arena_args),
"mps_arena_create");
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
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_FIRST_FIT, TRUE);
die(stress(arena, randomSize8, "MVFF", mps_class_mvff(), args),
"stress MVFF");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
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_FIRST_FIT, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, randomSize8, "MVFF debug", mps_class_mvff_debug(), args),
"stress MVFF debug");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, randomSize, "MV", mps_class_mv(), args),
"stress MV");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, randomSize, "MV debug", mps_class_mv_debug(), args),
"stress MV debug");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
fixedSizeSize = 1 + rnd() % 64;
MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize);
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 100000);
die(stress(arena, fixedSize, "MFS", mps_class_mfs(), args),
"stress MFS");
} MPS_ARGS_END(args);
printf("MV\n");
die(stress(mps_class_mv(), randomSize, arena,
(size_t)65536, (size_t)32, (size_t)65536),
"stress MV");
mps_arena_destroy(arena);
}
int main(int argc, char *argv[])
{
mps_arena_t arena;
testlib_init(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
testInArena(arena, &bothOptions);
mps_arena_destroy(arena);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
testInArena(mps_arena_class_vm(), args, &bothOptions);
} MPS_ARGS_END(args);
die(mps_arena_create(&arena, mps_arena_class_vm(), smallArenaSIZE),
"mps_arena_create");
testInArena(arena, &fenceOptions);
mps_arena_destroy(arena);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, smallArenaSIZE);
testInArena(mps_arena_class_vm(), args, &fenceOptions);
} MPS_ARGS_END(args);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;

View file

@ -326,9 +326,9 @@ typedef struct _mps_sac_s {
/* .sacc: Keep in sync with <code/sac.h>. */
typedef struct mps_sac_class_s {
size_t _block_size;
size_t _cached_count;
unsigned _frequency;
size_t mps_block_size;
size_t mps_cached_count;
unsigned mps_frequency;
} mps_sac_class_s;
#define mps_sac_classes_s mps_sac_class_s
@ -754,9 +754,9 @@ extern void mps_arena_roots_walk(mps_arena_t,
typedef struct mps_pool_debug_option_s {
const void *fence_template;
void *fence_template;
size_t fence_size;
const void *free_template;
void *free_template;
size_t free_size;
} mps_pool_debug_option_s;

View file

@ -9,22 +9,6 @@
#include "mps.h"
/* The mvt pool class has five extra parameters to mps_pool_create:
* mps_res_t mps_pool_create(mps_pool_t * pool, mps_arena_t arena,
* mps_class_t mvt_class,
* size_t minimum_size,
* size_t mean_size,
* size_t maximum_size,
* mps_count_t reserve_depth
* mps_count_t fragmentation_limit);
* minimum_, mean_, and maximum_size are the mimimum, mean, and
* maximum (typical) size of objects expected to be allocated in the
* pool. reserve_depth is a measure of the expected hysteresis of the
* object population. fragmentation_limit is a percentage (between 0
* and 100): if the free space managed by the pool exceeds the
* specified percentage, the pool will resort to a "first fit"
* allocation policy.
*/
extern mps_class_t mps_class_mvt(void);
/* The mvt pool class supports two extensions to the pool protocol:

79
mps/code/mpsw3.h Normal file
View file

@ -0,0 +1,79 @@
/* mpsw3.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE, WINDOWS PART
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .readership: customers, MPS developers.
* .sources: <design/interface-c/>.
*/
#ifndef mpsw3_h
#define mpsw3_h
#include "mps.h" /* needed for mps_tramp_t */
#include "mpswin.h" /* needed for SEH filter */
extern LONG mps_SEH_filter(LPEXCEPTION_POINTERS, void **, size_t *);
extern void mps_SEH_handler(void *, size_t);
#define mps_tramp(r_o, f, p, s) \
MPS_BEGIN \
void **_r_o = (r_o); \
mps_tramp_t _f = (f); \
void *_p = (p); \
size_t _s = (s); \
void *_hp = NULL; size_t _hs = 0; \
__try { \
*_r_o = (*_f)(_p, _s); \
} __except(mps_SEH_filter(GetExceptionInformation(), \
&_hp, &_hs)) { \
mps_SEH_handler(_hp, _hs); \
} \
MPS_END
#endif /* mpsw3_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -6,14 +6,10 @@
#include <stdio.h>
#include <stdarg.h>
#include "mpstd.h"
#include <time.h>
#include "mpscmvt.h"
#include "mps.h"
typedef mps_word_t mps_count_t; /* machine word (target dep.) */
#include "mpslib.h"
#include "mpsavm.h"
#include "testlib.h"
@ -71,11 +67,11 @@ static size_t randomSize(unsigned long i)
#define TEST_SET_SIZE 1234
#define TEST_LOOPS 27
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size, mps_align_t align)
{
mps_res_t res;
size = alignUp(size, MPS_PF_ALIGN);
size = alignUp(size, align);
do {
MPS_RESERVE_BLOCK(res, *p, ap, size);
@ -87,8 +83,9 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
}
static mps_res_t stress(mps_class_t class, mps_arena_t arena,
size_t (*size)(unsigned long i), mps_arg_s args[])
static mps_res_t stress(mps_arena_t arena, mps_align_t align,
size_t (*size)(unsigned long i),
mps_class_t class, mps_arg_s args[])
{
mps_res_t res;
mps_ap_t ap;
@ -105,7 +102,7 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
for(i=0; i<TEST_SET_SIZE; ++i) {
ss[i] = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
res = make((mps_addr_t *)&ps[i], ap, ss[i], align);
if(res != MPS_RES_OK)
ss[i] = 0;
else
@ -144,7 +141,7 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
/* allocate some new objects */
for(i=x; i<TEST_SET_SIZE; ++i) {
size_t s = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, s);
res = make((mps_addr_t *)&ps[i], ap, s, align);
if(res != MPS_RES_OK)
break;
ss[i] = s;
@ -166,33 +163,29 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
}
static void stress_with_arena_class(mps_arena_class_t aclass, Bool zoned)
static void test_in_arena(mps_arena_class_t arena_class, mps_arg_s *arena_args)
{
mps_arena_t arena;
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned);
die(mps_arena_create_k(&arena, aclass, args),
"mps_arena_create");
} MPS_ARGS_END(args);
die(mps_arena_create_k(&arena, arena_class, arena_args),
"mps_arena_create");
size_min = MPS_PF_ALIGN;
size_mean = 42;
size_max = 8192;
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_MIN_SIZE, size_min);
MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, size_mean);
MPS_ARGS_ADD(args, MPS_KEY_MAX_SIZE, size_max);
MPS_ARGS_ADD(args, MPS_KEY_MVT_RESERVE_DEPTH, TEST_SET_SIZE/2);
MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.3);
die(stress(mps_class_mvt(), arena, randomSize, args), "stress MVT");
die(stress(arena, align, randomSize, mps_class_mvt(), args), "stress MVT");
} MPS_ARGS_END(args);
mps_arena_destroy(arena);
return;
}
@ -200,8 +193,16 @@ int main(int argc, char *argv[])
{
testlib_init(argc, argv);
stress_with_arena_class(mps_arena_class_vm(), TRUE);
stress_with_arena_class(mps_arena_class_vm(), FALSE);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
test_in_arena(mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
test_in_arena(mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;

View file

@ -217,6 +217,7 @@ static void MVDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
static Res MVInit(Pool pool, ArgList args)
{
Align align = MV_ALIGN_DEFAULT;
Size extendBy = MV_EXTEND_BY_DEFAULT;
Size avgSize = MV_AVG_SIZE_DEFAULT;
Size maxSize = MV_MAX_SIZE_DEFAULT;
@ -226,6 +227,8 @@ static Res MVInit(Pool pool, ArgList args)
Res res;
ArgStruct arg;
if (ArgPick(&arg, args, MPS_KEY_ALIGN))
align = arg.val.align;
if (ArgPick(&arg, args, MPS_KEY_EXTEND_BY))
extendBy = arg.val.size;
if (ArgPick(&arg, args, MPS_KEY_MEAN_SIZE))
@ -233,12 +236,14 @@ static Res MVInit(Pool pool, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_MAX_SIZE))
maxSize = arg.val.size;
AVERT(Align, align);
AVER(extendBy > 0);
AVER(avgSize > 0);
AVER(avgSize <= extendBy);
AVER(maxSize > 0);
AVER(extendBy <= maxSize);
pool->alignment = align;
mv = Pool2MV(pool);
arena = PoolArena(pool);
@ -626,6 +631,7 @@ static void MVFree(Pool pool, Addr old, Size size)
AVERT(MV, mv);
AVER(old != (Addr)0);
AVER(AddrIsAligned(old, pool->alignment));
AVER(size > 0);
size = SizeAlignUp(size, pool->alignment);

View file

@ -261,7 +261,12 @@ static Res MVTInit(Pool pool, ArgList args)
fragLimit = (Count)(arg.val.d * 100);
}
AVER(SizeIsAligned(align, MPS_PF_ALIGN));
AVERT(Align, align);
/* This restriction on the alignment is necessary because of the use
* of a Freelist to store the free address ranges in low-memory
* situations. See <design/freelist/#impl.grain.align>.
*/
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
AVER(0 < minSize);
AVER(minSize <= meanSize);
AVER(meanSize <= maxSize);

View file

@ -456,7 +456,7 @@ static Res MVFFInit(Pool pool, ArgList args)
{
Size extendBy = MVFF_EXTEND_BY_DEFAULT;
Size avgSize = MVFF_AVG_SIZE_DEFAULT;
Size align = MVFF_ALIGN_DEFAULT;
Align align = MVFF_ALIGN_DEFAULT;
Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT;
Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT;
Bool firstFit = MVFF_FIRST_FIT_DEFAULT;
@ -500,7 +500,12 @@ static Res MVFFInit(Pool pool, ArgList args)
AVER(avgSize <= extendBy); /* .arg.check */
AVER(spare >= 0.0); /* .arg.check */
AVER(spare <= 1.0); /* .arg.check */
AVER(SizeIsAligned(align, MPS_PF_ALIGN));
AVERT(Align, align);
/* This restriction on the alignment is necessary because of the use
* of a Freelist to store the free address ranges in low-memory
* situations. <design/freelist/#impl.grain.align>.
*/
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
AVERT(Bool, slotHigh);
AVERT(Bool, arenaHigh);
AVERT(Bool, firstFit);

View file

@ -117,10 +117,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
/* to be large enough, but that gets complicated, if you have to */
/* merge classes because of the adjustment. */
for (i = 0; i < classesCount; ++i) {
AVER(classes[i]._block_size > 0);
AVER(SizeIsAligned(classes[i]._block_size, PoolAlignment(pool)));
AVER(prevSize < classes[i]._block_size);
prevSize = classes[i]._block_size;
AVER(classes[i].mps_block_size > 0);
AVER(SizeIsAligned(classes[i].mps_block_size, PoolAlignment(pool)));
AVER(prevSize < classes[i].mps_block_size);
prevSize = classes[i].mps_block_size;
/* no restrictions on count */
/* no restrictions on frequency */
}
@ -128,7 +128,7 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
/* Calculate frequency scale */
for (i = 0; i < classesCount; ++i) {
unsigned oldFreq = totalFreq;
totalFreq += classes[i]._frequency;
totalFreq += classes[i].mps_frequency;
AVER(oldFreq <= totalFreq); /* check for overflow */
UNUSED(oldFreq); /* <code/mpm.c#check.unused> */
}
@ -136,10 +136,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
/* Find middle one */
totalFreq /= 2;
for (i = 0; i < classesCount; ++i) {
if (totalFreq < classes[i]._frequency) break;
totalFreq -= classes[i]._frequency;
if (totalFreq < classes[i].mps_frequency) break;
totalFreq -= classes[i].mps_frequency;
}
if (totalFreq <= classes[i]._frequency / 2)
if (totalFreq <= classes[i].mps_frequency / 2)
middleIndex = i;
else
middleIndex = i + 1; /* there must exist another class at i+1 */
@ -155,9 +155,9 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
/* It's important this matches SACFind. */
esac = ExternalSACOfSAC(sac);
for (j = middleIndex + 1, i = 0; j < classesCount; ++j, i += 2) {
esac->_freelists[i]._size = classes[j]._block_size;
esac->_freelists[i]._size = classes[j].mps_block_size;
esac->_freelists[i]._count = 0;
esac->_freelists[i]._count_max = classes[j]._cached_count;
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
esac->_freelists[i]._blocks = NULL;
}
esac->_freelists[i]._size = SizeMAX;
@ -165,19 +165,19 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
esac->_freelists[i]._count_max = 0;
esac->_freelists[i]._blocks = NULL;
for (j = middleIndex, i = 1; j > 0; --j, i += 2) {
esac->_freelists[i]._size = classes[j-1]._block_size;
esac->_freelists[i]._size = classes[j-1].mps_block_size;
esac->_freelists[i]._count = 0;
esac->_freelists[i]._count_max = classes[j]._cached_count;
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
esac->_freelists[i]._blocks = NULL;
}
esac->_freelists[i]._size = 0;
esac->_freelists[i]._count = 0;
esac->_freelists[i]._count_max = classes[j]._cached_count;
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
esac->_freelists[i]._blocks = NULL;
/* finish init */
esac->_trapped = FALSE;
esac->_middle = classes[middleIndex]._block_size;
esac->_middle = classes[middleIndex].mps_block_size;
sac->pool = pool;
sac->classesCount = classesCount;
sac->middleIndex = middleIndex;

View file

@ -7,6 +7,7 @@
#include "mpscmv.h"
#include "mpscmvff.h"
#include "mpscmfs.h"
#include "mpslib.h"
#include "mpsavm.h"
#include "mps.h"
@ -15,9 +16,7 @@
#include "mpslib.h"
#include <stdio.h>
#include "mpstd.h"
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
@ -28,9 +27,6 @@
#define testSetSIZE 200
#define testLOOPS 10
#define topClassSIZE 0xA00
#define classCOUNT 4
/* make -- allocate an object */
@ -45,25 +41,36 @@ static mps_res_t make(mps_addr_t *p, mps_sac_t sac, size_t size)
/* stress -- create a pool of the requested type and allocate in it */
static mps_res_t stress(mps_class_t class,
size_t classes_count, mps_sac_classes_s *classes,
size_t (*size)(size_t i), mps_arena_t arena, ...)
static mps_res_t stress(mps_arena_t arena, mps_align_t align,
size_t (*size)(size_t i),
const char *name, mps_class_t pool_class,
mps_arg_s *args)
{
mps_res_t res;
mps_pool_t pool;
mps_sac_t sac;
va_list arg;
size_t i, k;
int *ps[testSetSIZE];
size_t ss[testSetSIZE];
mps_sac_classes_s classes[4] = {
{1, 1, 1},
{2, 1, 2},
{16, 9, 5},
{100, 9, 4}
};
size_t classes_count = sizeof classes / sizeof *classes;
for (i = 0; i < classes_count; ++i) {
classes[i].mps_block_size *= alignUp(align, sizeof(void *));
}
va_start(arg, arena);
res = mps_pool_create_v(&pool, arena, class, arg);
va_end(arg);
printf("%s\n", name);
res = mps_pool_create_k(&pool, arena, pool_class, args);
if (res != MPS_RES_OK)
return res;
die(mps_sac_create(&sac, pool, classes_count, classes), "SACCreate");
die(mps_sac_create(&sac, pool, classes_count, classes),
"SACCreate");
/* allocate a load of objects */
for (i = 0; i < testSetSIZE; ++i) {
@ -125,9 +132,9 @@ static mps_res_t stress(mps_class_t class,
}
/* randomSize8 -- produce sizes both latge and small */
/* randomSize -- produce sizes both large and small */
static size_t randomSize8(size_t i)
static size_t randomSize(size_t i)
{
size_t maxSize = 2 * 160 * 0x2000;
size_t size;
@ -138,58 +145,97 @@ static size_t randomSize8(size_t i)
}
/* testInArena -- test all the pool classes in the given arena */
/* fixedSize -- produce always the same size */
static size_t fixedSizeSize = 0;
static size_t fixedSize(size_t i)
{
testlib_unused(i);
return fixedSizeSize;
}
static mps_pool_debug_option_s debugOptions = {
/* .fence_template = */ (const void *)"postpostpostpost",
/* .fence_size = */ MPS_PF_ALIGN,
/* .free_template = */ (const void *)"DEAD",
/* .fence_template = */ (void *)"post",
/* .fence_size = */ 4,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_sac_classes_s classes[4] = {
{MPS_PF_ALIGN, 1, 1},
{MPS_PF_ALIGN * 2, 1, 2},
{128 + MPS_PF_ALIGN, 9, 5},
{topClassSIZE, 9, 4}
};
static void testInArena(mps_arena_t arena)
/* testInArena -- test all the pool classes in the given arena */
static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args)
{
printf("MVFF\n\n");
die(stress(mps_class_mvff(), classCOUNT, classes, randomSize8, arena,
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE),
"stress MVFF");
printf("MV debug\n\n");
die(stress(mps_class_mv_debug(), classCOUNT, classes, randomSize8, arena,
&debugOptions, (size_t)65536, (size_t)32, (size_t)65536),
"stress MV debug");
printf("MV\n\n");
die(stress(mps_class_mv(), classCOUNT, classes, randomSize8, arena,
(size_t)65536, (size_t)32, (size_t)65536),
"stress MV");
mps_arena_t arena;
die(mps_arena_create_k(&arena, arena_class, arena_args),
"mps_arena_create");
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
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_FIRST_FIT, TRUE);
die(stress(arena, align, randomSize, "MVFF", mps_class_mvff(), args),
"stress MVFF");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
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_FIRST_FIT, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions);
die(stress(arena, align, randomSize, "MVFF debug",
mps_class_mvff_debug(), args),
"stress MVFF debug");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, align, randomSize, "MV", mps_class_mv(), args),
"stress MV");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = 1 << (rnd() % 6);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions);
die(stress(arena, align, randomSize, "MV debug",
mps_class_mv_debug(), args),
"stress MV debug");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
fixedSizeSize = sizeof(void *) * (1 + rnd() % 100);
MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize);
die(stress(arena, fixedSizeSize, fixedSize, "MFS", mps_class_mfs(), args),
"stress MFS");
} MPS_ARGS_END(args);
mps_arena_destroy(arena);
}
int main(int argc, char *argv[])
{
mps_arena_t arena;
testlib_init(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
testInArena(arena);
mps_arena_destroy(arena);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
testInArena(mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
testInArena(mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
testInArena(arena);
mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;

View file

@ -70,6 +70,11 @@ an ``AVER()`` has fired. Naturally, if the information required for
the dump has been corrupted, it will fail, as softly as possible
(source @@@@).
_`.req.portable`: Client code that uses these features must be easily
portable to all the supported platforms. (Source: job003749_.)
.. _job003749: http://www.ravenbrook.com/project/mps/issue/job003749/
.. note::
There are more requirements, especially about memory dumps and
@ -90,6 +95,11 @@ specified as a byte/word which used repeatedly to fill the fencepost.
_`.fence.content.template`: The content could be given as a template
which is of the right size and is simply copied onto the fencepost.
_`.fence.content.template.repeat`: The content could be given as a
template which is copied repeatedly until the fencepost is full. (This
would avoid the need to specify different templates on different
architectures, and so help meet `.req.portable`_.)
_`.fence.walk`: `.req.fencepost.check`_ requires the ability to find
all the allocated objects. In formatted pools, this is not a problem.
In unformatted pools, we could use the walker. It's a feasible
@ -233,14 +243,14 @@ to pools. In particular, clients will be able to use tagging and
fenceposting separately on each pool.
_`.fence.size`: Having fenceposts of adjustable size and pattern is
quite useful. We feel that restricting the size to an integral
multiple of the [pool or format?] alignment is harmless and simplifies
the implementation enormously.
useful. Restricting the size to an integral multiple of the [pool or
format?] alignment would simplify the implementation but breaks
`.req.portable`_.
_`.fence.template`: We use templates (`.fence.content.template`_) to
fill in the fenceposts, but we do not give any guarantees about the
location of the fenceposts, only that they're properly aligned. This
leaves us the opportunity to do tail-only fenceposting, if we choose.
location of the fenceposts. This leaves us the opportunity to do
tail-only fenceposting, if we choose.
_`.fence.slop`: [see impl.c.dbgpool.FenceAlloc @@@@]
@ -416,6 +426,8 @@ Document History
- 2013-04-14 GDR_ Converted to reStructuredText.
- 2014-04-09 GDR_ Added newly discovered requirement `.req.portable`_.
.. _RB: http://www.ravenbrook.com/consultants/rb/
.. _GDR: http://www.ravenbrook.com/consultants/gdr/

View file

@ -114,7 +114,7 @@ May contain exact references? [4]_ yes --- yes yes ---
May contain ambiguous references? [4]_ no --- no no --- --- --- --- --- no
May contain weak references? [4]_ no --- no yes --- --- --- --- --- no
Allocations fixed or variable in size? var var var var var fixed var var var var
Alignment? [5]_ conf conf conf conf conf [6]_ [6]_ [7]_ [7]_ conf
Alignment? [5]_ conf conf conf conf conf [6]_ conf [7]_ [7]_ conf
Dependent objects? [8]_ no --- no yes --- --- --- --- --- no
May use remote references? [9]_ no --- no no --- --- --- --- --- no
Blocks are automatically managed? [10]_ yes yes yes yes yes no no no no no
@ -151,13 +151,13 @@ Blocks may use :term:`in-band headers`? yes yes yes yes yes
.. [5] "Alignment" is "conf" if the client program may specify
:term:`alignment` for each pool.
.. [6] The alignment of blocks allocated from :ref:`pool-mv` pools
is platform-dependent.
.. [6] The alignment of blocks allocated from :ref:`pool-mfs`
pools is the platform's :term:`natural alignment`,
:c:macro:`MPS_PF_ALIGN`.
.. [7] :ref:`pool-mvt` and :ref:`pool-mvff` pools have
configurable alignment, but it may not be smaller than the
:term:`natural alignment` for the :term:`platform` (see
:c:macro:`MPS_PF_ALIGN`).
configurable alignment, but it may not be smaller than
``sizeof(void *)``.
.. [8] In pools with this property, each object may specify an
:term:`dependent object` which the client program

View file

@ -38,9 +38,7 @@ MV properties
* Allocations may be variable in size.
* The :term:`alignment` of blocks is not configurable: it is the
:term:`natural alignment` of the platform (see
:c:macro:`MPS_PF_ALIGN`).
* The :term:`alignment` of blocks is configurable.
* Blocks do not have :term:`dependent objects`.
@ -73,7 +71,13 @@ MV interface
:term:`pool`.
When creating an MV pool, :c:func:`mps_pool_create_k` may take
three :term:`keyword arguments`:
the following :term:`keyword arguments`:
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
:term:`alignment` of addresses for allocation (and freeing) in
the pool. If an unaligned size is passed to :c:func:`mps_alloc` or
:c:func:`mps_free`, it will be rounded up to the pool's alignment.
* :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
default 65536) is the :term:`size` of segment that the pool will
@ -119,10 +123,11 @@ MV interface
class.
When creating a debugging MV pool, :c:func:`mps_pool_create_k`
takes four keyword arguments: :c:macro:`MPS_KEY_EXTEND_SIZE`,
:c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE` are as
described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`
specifies the debugging options. See :c:type:`mps_debug_option_s`.
takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`,
:c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`,
:c:macro:`MPS_KEY_MAX_SIZE` are as described above, and
:c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging
options. See :c:type:`mps_debug_option_s`.
.. deprecated:: starting with version 1.112.

View file

@ -80,7 +80,7 @@ MVFF properties
* Allocations may be variable in size.
* The :term:`alignment` of blocks is configurable, but may not be
smaller than the :term:`natural alignment` of the platform.
smaller than ``sizeof(void *)``.
* Blocks do not have :term:`dependent objects`.
@ -127,10 +127,10 @@ MVFF interface
* :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the
:term:`alignment` of addresses for allocation (and freeing) in
the pool. If an unaligned size is passed to :c:func:`mps_alloc` or
:c:func:`mps_free`, it will be rounded up to the pool's alignment.
The minimum alignment supported by pools of this class is
``sizeof(void *)``.
the pool. If an unaligned size is passed to :c:func:`mps_alloc`
or :c:func:`mps_free`, it will be rounded up to the pool's
alignment. The minimum alignment supported by pools of this
class is ``sizeof(void *)``.
* :c:macro:`MPS_KEY_SPARE` (type :c:type:`double`, default 0.75)
is the maximum proportion of memory that the pool will keep

View file

@ -78,6 +78,9 @@ MVT properties
* Allocations may be variable in size.
* The :term:`alignment` of blocks is configurable, but may not be
smaller than ``sizeof(void *)``.
* Blocks do not have :term:`dependent objects`.
* Blocks are not automatically :term:`reclaimed`.
@ -117,7 +120,7 @@ MVT interface
the pool. If an unaligned size is passed to :c:func:`mps_alloc` or
:c:func:`mps_free`, it will be rounded up to the pool's alignment.
The minimum alignment supported by pools of this class is
``sizeof(void *)``.
``sizeof(void *)``.
* :c:macro:`MPS_KEY_MIN_SIZE` (type :c:type:`size_t`, default is
:c:macro:`MPS_PF_ALIGN`) is the

View file

@ -40,10 +40,23 @@ New features
the lowest generation whose new size was within its capacity.)
Interface changes
.................
#. It is now possible to configure the alignment of objects allocated
in a :ref:`pool-mv` pool, by passing the :c:macro:`MPS_KEY_ALIGN`
keyword argument to :c:func:`mps_pool_create_k`.
#. The alignment requirements for :ref:`pool-mvff` and :ref:`pool-mvt`
pools have been relaxed on the platforms ``w3i3mv`` and ``w3i6mv``.
On all platforms it is now possible to specify alignments down to
``sizeof(void *)`` as the alignment for pools of these classes.
#. The sizes of the templates in a :c:type:`mps_pool_debug_option_s`
structure no longer have to be related to the alignment of the
pools that they are used with. This makes it easier to reuse these
structures.
#. There is now a default value (currently 1 \ :term:`megabyte`) for
the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to
:c:func:`mps_arena_create_k` when creating a virtual memory arena.
@ -81,6 +94,12 @@ Other changes
.. _job003745: https://www.ravenbrook.com/project/mps/issue/job003745/
#. The debugging version of the :ref:`pool-mvff` pool class,
:c:func:`mps_class_mvff_debug`, no longer triggers an assertion
failure if you allocate a large object. See job003751_.
.. _job003751: https://www.ravenbrook.com/project/mps/issue/job003751/
#. :program:`mpseventtxt` now successfully processes a telemetry log
containing multiple labels associated with the same address. See
job003756_.

View file

@ -170,9 +170,9 @@ Cache interface
The size classes are described by an array of element type
:c:type:`mps_sac_class_s`. This array is used to initialize the
segregated allocation cache, and is not needed
after:c:func:`mps_sac_create` returns. The following constraints
apply to the array:
segregated allocation cache, and is not needed after
:c:func:`mps_sac_create` returns. The following constraints apply
to the array:
* You must specify at least one size class.

View file

@ -50,7 +50,7 @@ debugging:
for the pattern at any time by calling
:c:func:`mps_pool_check_free_space`.
The :term:`client program` specifies templates for both of these
The :term:`client program` may specify templates for both of these
features via the :c:type:`mps_pool_debug_option_s` structure. This
allows it to specify patterns:
@ -66,8 +66,8 @@ allows it to specify patterns:
For example::
mps_pool_debug_option_s debug_options = {
(const void *)"postpost", 8,
(const void *)"freefree", 8,
"fencepost", 9,
"free", 4,
};
mps_pool_t pool;
mps_res_t res;
@ -87,9 +87,9 @@ For example::
class`. ::
typedef struct mps_pool_debug_option_s {
const void *fence_template;
void *fence_template;
size_t fence_size;
const void *free_template;
void *free_template;
size_t free_size;
} mps_pool_debug_option_s;
@ -104,10 +104,6 @@ For example::
``free_size`` is the :term:`size` of ``free_template`` in bytes, or
zero if the debugging pool should not splat free space.
Both ``fence_size`` and ``free_size`` must be a multiple of the
:term:`alignment` of the :term:`pool`, and also a multiple of the
alignment of the pool's :term:`object format` if it has one.
The debugging pool will copy the ``fence_size`` bytes pointed to by
``fence_template`` in a repeating pattern onto each fencepost during
allocation, and it will copy the bytes pointed to by

View file

@ -86,7 +86,7 @@ now :c:macro:`MPS_KEY_ARGS_END`.
Keyword Type & field in ``arg.val`` See
======================================== ====================================================== ==========================================================
:c:macro:`MPS_KEY_ARGS_END` *none* *see above*
:c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
:c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt`
:c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams`
:c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`