From 217831cc47e7b2a4c02513cd8f3dddf32604faa5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 19 May 2013 14:27:24 +0100 Subject: [PATCH] Remove "emergency" free list allocator from the cbs module (it belongs in its own module) and update clients and the design accordingly. Copied from Perforce Change: 181927 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 613 +------------------------------------------- mps/code/cbs.h | 15 -- mps/code/cbstest.c | 2 +- mps/code/poolmv2.c | 2 +- mps/code/poolmvff.c | 6 +- mps/design/cbs.rst | 158 +----------- 6 files changed, 21 insertions(+), 775 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index a9cb0d0b087..f40d075b27e 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -21,9 +21,6 @@ SRCID(cbs, "$Id$"); -/* See */ -#define cbsMinimumAlignment ((Align)sizeof(void *)) - #define cbsOfSplayTree(tree) PARENT(CBSStruct, splayTree, (tree)) #define cbsBlockOfSplayNode(node) PARENT(CBSBlockStruct, splayNode, (node)) #define splayTreeOfCBS(tree) (&((cbs)->splayTree)) @@ -31,55 +28,6 @@ SRCID(cbs, "$Id$"); #define keyOfCBSBlock(block) ((void *)&((block)->base)) -/* CBSEmergencyBlock* -- Getters and setters for emergency blocks - * - * See . - */ - -#define CBSEmergencyBlockBase(block) ((Addr)(block)) -#define CBSEmergencyBlockLimit(block) ((Addr)((block)[1])) -#define CBSEmergencyBlockSize(block) \ - (AddrOffset(CBSEmergencyBlockBase(block), CBSEmergencyBlockLimit(block))) -#define CBSEmergencyBlockNext(block) ((CBSEmergencyBlock)((block)[0])) - -#define CBSEmergencyBlockSetNext(block, next) \ - BEGIN (block)[0] = (void *)(next); END -#define CBSEmergencyBlockSetLimit(block, limit) \ - BEGIN (block)[1] = (void *)(limit); END - - -/* CBSEmergencyGrain* -- Getters and setters for emergency grains - * - * See . - */ - -#define CBSEmergencyGrainBase(grain) ((Addr)(grain)) -#define CBSEmergencyGrainLimit(cbs, grain) \ - AddrAdd(CBSEmergencyGrainBase(grain), CBSEmergencyGrainSize(cbs)) -#define CBSEmergencyGrainSize(cbs) ((cbs)->alignment) -#define CBSEmergencyGrainNext(grain) ((CBSEmergencyGrain)((grain)[0])) - -#define CBSEmergencyGrainSetNext(grain, next) \ - BEGIN (grain)[0] = (void *)(next); END - - -static CBSEmergencyBlock CBSEmergencyBlockInit(Addr base, Addr limit) -{ - CBSEmergencyBlock block = (CBSEmergencyBlock)base; - CBSEmergencyBlockSetNext(block, NULL); - CBSEmergencyBlockSetLimit(block, limit); - return block; -} - -static CBSEmergencyGrain CBSEmergencyGrainInit(CBS cbs, Addr base, Addr limit) -{ - CBSEmergencyGrain grain = (CBSEmergencyGrain)base; - AVER(AddrOffset(base, limit) == CBSEmergencyGrainSize(cbs)); - CBSEmergencyGrainSetNext(grain, NULL); - return grain; -} - - /* CBSEnter, CBSLeave -- Avoid re-entrance * * .enter-leave: The callbacks are restricted in what they may call. @@ -115,20 +63,12 @@ Bool CBSCheck(CBS cbs) CHECKL(SplayTreeCheck(splayTreeOfCBS(cbs))); /* nothing to check about splayTreeSize */ CHECKD(Pool, cbs->blockPool); - CHECKL(BoolCheck(cbs->mayUseInline)); CHECKL(BoolCheck(cbs->fastFind)); CHECKL(BoolCheck(cbs->inCBS)); CHECKL(cbs->new == NULL || FUNCHECK(cbs->new)); CHECKL(cbs->delete == NULL || FUNCHECK(cbs->delete)); CHECKL(cbs->grow == NULL || FUNCHECK(cbs->grow)); CHECKL(cbs->shrink == NULL || FUNCHECK(cbs->shrink)); - CHECKL(cbs->mayUseInline || cbs->emergencyBlockList == NULL); - CHECKL(cbs->mayUseInline || cbs->emergencyGrainList == NULL); - /* See */ - CHECKL(!cbs->mayUseInline || - AlignIsAligned(cbs->alignment, cbsMinimumAlignment)); - /* can't check emergencyBlockList or emergencyGrainList more */ - /* Checking eblSize and eglSize is too laborious without a List ADT */ /* No MeterCheck */ return TRUE; @@ -270,19 +210,13 @@ Res CBSInit(Arena arena, CBS cbs, void *owner, CBSChangeSizeMethod new, CBSChangeSizeMethod delete, CBSChangeSizeMethod grow, CBSChangeSizeMethod shrink, Size minSize, Align alignment, - Bool mayUseInline, Bool fastFind) + Bool fastFind) { Res res; AVERT(Arena, arena); AVER(new == NULL || FUNCHECK(new)); AVER(delete == NULL || FUNCHECK(delete)); - AVER(BoolCheck(mayUseInline)); - if (mayUseInline) { - /* See */ - if (!AlignIsAligned(alignment, cbsMinimumAlignment)) - return ResPARAM; - } SplayTreeInit(splayTreeOfCBS(cbs), &cbsSplayCompare, fastFind ? &cbsUpdateNode : NULL); @@ -297,18 +231,11 @@ Res CBSInit(Arena arena, CBS cbs, void *owner, cbs->grow = grow; cbs->shrink = shrink; cbs->minSize = minSize; - cbs->mayUseInline = mayUseInline; cbs->fastFind = fastFind; cbs->alignment = alignment; cbs->inCBS = TRUE; - cbs->emergencyBlockList = NULL; - cbs->eblSize = 0; - cbs->emergencyGrainList = NULL; - cbs->eglSize = 0; METER_INIT(cbs->splaySearch, "size of splay tree", (void *)cbs); - METER_INIT(cbs->eblSearch, "size of emergencyBlockList", (void *)cbs); - METER_INIT(cbs->eglSearch, "size of emergencyGrainList", (void *)cbs); cbs->sig = CBSSig; @@ -330,15 +257,11 @@ void CBSFinish(CBS cbs) CBSEnter(cbs); METER_EMIT(&cbs->splaySearch); - METER_EMIT(&cbs->eblSearch); - METER_EMIT(&cbs->eglSearch); cbs->sig = SigInvalid; SplayTreeFinish(splayTreeOfCBS(cbs)); PoolDestroy(cbs->blockPool); - cbs->emergencyBlockList = NULL; - cbs->emergencyGrainList = NULL; } @@ -557,275 +480,6 @@ fail: } -/* cbsCoalesceWithEmergencyLists -- coalesce received range with EBL and EGL - * - * Attempts to extend the range about to be freed by adding ranges from - * the emergency lists. May remove blocks from the emergency list. - */ - -static Res cbsCoalesceWithEmergencyLists(Addr *baseIO, Addr *limitIO, CBS cbs) -{ - Addr base, limit; - Count nCoalescences = 0; - - AVER(baseIO != NULL); - AVER(limitIO != NULL); - AVERT(CBS, cbs); - AVER(cbs->mayUseInline); - - base = *baseIO; - limit = *limitIO; - AVER(base < limit); - - if (cbs->emergencyBlockList != NULL) { - CBSEmergencyBlock prev, block, next; - Addr blockBase, blockLimit; - - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(block = cbs->emergencyBlockList, prev = NULL; - block != NULL && CBSEmergencyBlockBase(block) <= limit; - block = CBSEmergencyBlockNext(block)) { - - blockBase = CBSEmergencyBlockBase(block); - blockLimit = CBSEmergencyBlockLimit(block); - AVER(blockBase < blockLimit); - - if (prev != NULL) - AVER(CBSEmergencyBlockLimit(prev) < blockBase); - - if (blockLimit == base) { - base = blockBase; - next = CBSEmergencyBlockNext(block); - if (prev == NULL) - cbs->emergencyBlockList = next; - else - CBSEmergencyBlockSetNext(prev, next); - ++nCoalescences; - STATISTIC(--cbs->eblSize); - AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0); - } else if (blockBase == limit) { - limit = blockLimit; - next = CBSEmergencyBlockNext(block); - if (prev == NULL) - cbs->emergencyBlockList = next; - else - CBSEmergencyBlockSetNext(prev, next); - ++nCoalescences; - STATISTIC(--cbs->eblSize); - AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0); - /* For loop will stop at next test */ - } else if (blockLimit > base) { - return ResFAIL; /* range intersects block */ - } else { - prev = block; /* Only move prev if we didn't delete */ - } - } - /* block's next is still valid, even if it's been coalesced */ - } - - if (cbs->emergencyGrainList != NULL) { - CBSEmergencyGrain prev, grain, next; - Addr grainBase, grainLimit; - - METER_ACC(cbs->eglSearch, cbs->eglSize); - for(grain = cbs->emergencyGrainList, prev = NULL; - grain != NULL && CBSEmergencyGrainBase(grain) <= limit && - nCoalescences < 2; - grain = CBSEmergencyGrainNext(grain)) { - grainBase = CBSEmergencyGrainBase(grain); - grainLimit = CBSEmergencyGrainLimit(cbs, grain); - AVER(grainBase < grainLimit); - - if (prev != NULL) - AVER(CBSEmergencyGrainLimit(cbs, prev) < grainBase); - - if (grainLimit == base) { - base = grainBase; - next = CBSEmergencyGrainNext(grain); - if (prev == NULL) - cbs->emergencyGrainList = next; - else - CBSEmergencyGrainSetNext(prev, next); - ++nCoalescences; - STATISTIC(--cbs->eglSize); - AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0); - } else if (grainBase == limit) { - limit = grainLimit; - next = CBSEmergencyGrainNext(grain); - if (prev == NULL) - cbs->emergencyGrainList = next; - else - CBSEmergencyGrainSetNext(prev, next); - ++nCoalescences; - STATISTIC(--cbs->eglSize); - AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0); - break; - } else if (grainLimit > base) { - return ResFAIL; /* range intersects grain */ - } else { - prev = grain; - } - } - /* grain's next is still valid, even if it's been coalesced */ - } - - /* Because the lists are known to have isolated ranges, there can */ - /* be no more than 2 coalescences. */ - AVER(nCoalescences <= 2); - - *baseIO = base; - *limitIO = limit; - return ResOK; -} - - -/* cbsAddToEmergencyLists -- Adds range to emergency lists - * - * The range must be unadjacent to any items on the emergency lists. - */ - -static Res cbsAddToEmergencyLists(CBS cbs, Addr base, Addr limit) -{ - Res res = ResOK; - Size size; - - AVERT(CBS, cbs); - AVER(base < limit); - AVER(cbs->mayUseInline); - - size = AddrOffset(base, limit); - /* Use the block list if possible. See . */ - if (size > cbsMinimumAlignment) { - CBSEmergencyBlock prev, block, new; - new = CBSEmergencyBlockInit(base, limit); - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(prev = NULL, block = cbs->emergencyBlockList; - block != NULL && CBSEmergencyBlockBase(block) < base; - prev = block, block = CBSEmergencyBlockNext(block)) { - if (prev != NULL) - AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block)); - AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block)); - } - - if (prev != NULL && block != NULL) - AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block)); - - /* check ordering: prev ... new ... block */ - if (prev != NULL && CBSEmergencyBlockLimit(prev) >= base) - return ResFAIL; /* range intersects with existing block */ - - if (block != NULL && limit >= CBSEmergencyBlockBase(block)) - return ResFAIL; /* range intersects with existing block */ - - if (prev == NULL) - cbs->emergencyBlockList = new; - else - CBSEmergencyBlockSetNext(prev, new); - CBSEmergencyBlockSetNext(new, block); /* may be NULL */ - STATISTIC(++cbs->eblSize); - } else if (size == CBSEmergencyGrainSize(cbs)) { - CBSEmergencyGrain prev, grain, new; - new = CBSEmergencyGrainInit(cbs, base, limit); - METER_ACC(cbs->eglSearch, cbs->eglSize); - for(prev = NULL, grain = cbs->emergencyGrainList; - grain != NULL && CBSEmergencyGrainBase(grain) < base; - prev = grain, grain = CBSEmergencyGrainNext(grain)) { - if (prev != NULL) - AVER(CBSEmergencyGrainLimit(cbs, prev) < - CBSEmergencyGrainBase(grain)); - } - - if (prev != NULL && grain != NULL) - AVER(CBSEmergencyGrainLimit(cbs, prev) < CBSEmergencyGrainBase(grain)); - - /* check ordering: prev ... new ... grain */ - if (prev != NULL && CBSEmergencyGrainLimit(cbs, prev) >= base) - return ResFAIL; /* range intersects with existing grain */ - - if (grain != NULL && limit >= CBSEmergencyGrainBase(grain)) - return ResFAIL; /* range intersects with existing grain */ - - if (prev == NULL) - cbs->emergencyGrainList = new; - else - CBSEmergencyGrainSetNext(prev, new); - CBSEmergencyGrainSetNext(new, grain); /* may be NULL */ - STATISTIC(++cbs->eglSize); - } else { - NOTREACHED; - res = ResFAIL; /* in case AVERs are compiled out */ - } - - return res; -} - - -/* cbsFlushEmergencyLists -- Attempt to move ranges to CBS proper */ - -static void cbsFlushEmergencyLists(CBS cbs) -{ - Res res = ResOK; - Addr base, limit; - - AVERT(CBS, cbs); - AVER(cbs->mayUseInline); - - if (cbs->emergencyBlockList != NULL) { - CBSEmergencyBlock block; - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(block = cbs->emergencyBlockList; - block != NULL; - block = CBSEmergencyBlockNext(block)) { - AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block)); - res = cbsInsertIntoTree(&base, &limit, - cbs, CBSEmergencyBlockBase(block), - CBSEmergencyBlockLimit(block)); - if (res == ResOK) { - AVER(cbs->emergencyBlockList == block); - /* Emergency block is isolated in CBS */ - AVER(base == CBSEmergencyBlockBase(block)); - AVER(limit == CBSEmergencyBlockLimit(block)); - - cbs->emergencyBlockList = CBSEmergencyBlockNext(block); - STATISTIC(--cbs->eblSize); - AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0); - } else { - AVER(ResIsAllocFailure(res)); - goto done; - } - } - } - - if (cbs->emergencyGrainList != NULL) { - CBSEmergencyGrain grain; - METER_ACC(cbs->eglSearch, cbs->eglSize); - for(grain = cbs->emergencyGrainList; - grain != NULL; - grain = CBSEmergencyGrainNext(grain)) { - res = cbsInsertIntoTree(&base, &limit, - cbs, CBSEmergencyGrainBase(grain), - CBSEmergencyGrainLimit(cbs, grain)); - if (res == ResOK) { - AVER(cbs->emergencyGrainList == grain); - /* Emergency grain is isolated in CBS */ - AVER(base == CBSEmergencyGrainBase(grain)); - AVER(limit == CBSEmergencyGrainLimit(cbs, grain)); - - cbs->emergencyGrainList = CBSEmergencyGrainNext(grain); - STATISTIC(--cbs->eglSize); - AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0); - } else { - AVER(ResIsAllocFailure(res)); - goto done; - } - } - } - - done: - return; -} - - /* CBSInsert -- Insert a range into the CBS * * See . @@ -845,34 +499,7 @@ Res CBSInsertReturningRange(Addr *baseReturn, Addr *limitReturn, AVER(AddrIsAligned(base, cbs->alignment)); AVER(AddrIsAligned(limit, cbs->alignment)); - if (cbs->mayUseInline) { - newBase = base; - newLimit = limit; - - res = cbsCoalesceWithEmergencyLists(&newBase, &newLimit, cbs); - if (res != ResOK) { - AVER(res == ResFAIL); - goto done; - } - - res = cbsInsertIntoTree(&newBase, &newLimit, cbs, newBase, newLimit); - /* newBase and newLimit only changed if res == ResOK */ - - if (ResIsAllocFailure(res)) { - res = cbsAddToEmergencyLists(cbs, newBase, newLimit); - if (res != ResOK) { - AVER(res == ResFAIL); - goto done; - } - } else { - /* Attempt to clear emergency lists */ - cbsFlushEmergencyLists(cbs); - } - } else { - res = cbsInsertIntoTree(&newBase, &newLimit, cbs, base, limit); - } - - done: + res = cbsInsertIntoTree(&newBase, &newLimit, cbs, base, limit); if (res == ResOK) { AVER(newBase <= base); AVER(limit <= newLimit); @@ -950,12 +577,7 @@ static Res cbsDeleteFromTree(CBS cbs, Addr base, Addr limit) res = cbsBlockNew(cbs, limit, oldLimit); if (res != ResOK) { AVER(ResIsAllocFailure(res)); - if (cbs->mayUseInline) { - res = cbsAddToEmergencyLists(cbs, limit, oldLimit); - AVER(res == ResOK); - } else { - goto failNew; - } + goto failNew; } } else { /* right fragment is larger */ Addr oldBase = cbsBlock->base; @@ -966,12 +588,7 @@ static Res cbsDeleteFromTree(CBS cbs, Addr base, Addr limit) res = cbsBlockNew(cbs, oldBase, base); if (res != ResOK) { AVER(ResIsAllocFailure(res)); - if (cbs->mayUseInline) { - res = cbsAddToEmergencyLists(cbs, oldBase, base); - AVER(res == ResOK); - } else { - goto failNew; - } + goto failNew; } } } @@ -987,101 +604,6 @@ failSplayTreeSearch: } -static Res cbsDeleteFromEmergencyBlockList(CBS cbs, Addr base, Addr limit) -{ - Res res; - Addr blockBase, blockLimit; - CBSEmergencyBlock prev, block; - - /* parameters already checked in caller */ - AVER(cbs->mayUseInline); - - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(prev = NULL, block = cbs->emergencyBlockList; - block != NULL && CBSEmergencyBlockLimit(block) < limit; - prev = block, block = CBSEmergencyBlockNext(block)) { - AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block)); - if (CBSEmergencyBlockBase(block) >= base) - return ResFAIL; - if (prev != NULL) - AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block)); - } - - if (block != NULL) { - blockBase = CBSEmergencyBlockBase(block); - blockLimit = CBSEmergencyBlockLimit(block); - AVER(blockBase < blockLimit); - AVER(blockLimit >= limit); - - if (blockBase <= base && limit <= blockLimit) { - /* remove from list */ - if (prev == NULL) - cbs->emergencyBlockList = CBSEmergencyBlockNext(block); - else - CBSEmergencyBlockSetNext(prev, CBSEmergencyBlockNext(block)); - STATISTIC(--cbs->eblSize); - AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0); - if (blockBase < base) { - res = cbsAddToEmergencyLists(cbs, blockBase, base); - if (res != ResOK) - return res; - } - if (limit < blockLimit) { - res = cbsAddToEmergencyLists(cbs, limit, blockLimit); - if (res != ResOK) - return res; - } - return ResOK; - } else { - return ResFAIL; /* partly in list */ - } - } - return ResFAIL; /* not in list at all */ -} - - -static Res cbsDeleteFromEmergencyGrainList(CBS cbs, Addr base, Addr limit) -{ - Addr grainBase, grainLimit; - CBSEmergencyGrain prev, grain; - - /* parameters already checked in caller */ - AVER(cbs->mayUseInline); - if (AddrOffset(base, limit) != CBSEmergencyGrainSize(cbs)) - return ResFAIL; - - METER_ACC(cbs->eglSearch, cbs->eglSize); - for(prev = NULL, grain = cbs->emergencyGrainList; - grain != NULL && CBSEmergencyGrainLimit(cbs, grain) < limit; - prev = grain, grain = CBSEmergencyGrainNext(grain)) { - if (prev != NULL) - AVER(CBSEmergencyGrainLimit(cbs, prev) < CBSEmergencyGrainBase(grain)); - } - - if (grain != NULL) { - grainBase = CBSEmergencyGrainBase(grain); - grainLimit = CBSEmergencyGrainLimit(cbs, grain); - AVER(grainLimit >= limit); - - if (grainBase <= base && limit <= grainLimit) { - AVER(grainBase == base); - AVER(grainLimit == limit); - /* remove from list */ - if (prev == NULL) - cbs->emergencyGrainList = CBSEmergencyGrainNext(grain); - else - CBSEmergencyGrainSetNext(prev, CBSEmergencyGrainNext(grain)); - STATISTIC(--cbs->eglSize); - AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0); - return ResOK; - } else { - return ResFAIL; /* range is partly in list */ - } - } - return ResFAIL; /* range is not in list at all */ -} - - /* CBSDelete -- Remove a range from a CBS * * See . @@ -1101,21 +623,6 @@ Res CBSDelete(CBS cbs, Addr base, Addr limit) res = cbsDeleteFromTree(cbs, base, limit); - /* We rely on the consistency of the three free structures. */ - /* These checks don't distinguish "partially in" from "not in". */ - if (cbs->mayUseInline) { - AVER(res == ResOK || res == ResFAIL); - if (res == ResFAIL) { /* wasn't in tree */ - res = cbsDeleteFromEmergencyBlockList(cbs, base, limit); - if (res == ResFAIL) { /* wasn't in block list */ - res = cbsDeleteFromEmergencyGrainList(cbs, base, limit); - } - } - /* always worth trying, wherever we found the deleted block */ - if (res == ResOK) - cbsFlushEmergencyLists(cbs); - } - CBSLeave(cbs); return res; } @@ -1383,8 +890,6 @@ Bool CBSFindFirst(Addr *baseReturn, Addr *limitReturn, AVER(cbs->fastFind); AVERT(CBSFindDelete, findDelete); - cbsFlushEmergencyLists(cbs); /* might do some good */ - { SplayNode node; @@ -1403,38 +908,6 @@ Bool CBSFindFirst(Addr *baseReturn, Addr *limitReturn, } } - if (cbs->emergencyBlockList != NULL) { - CBSEmergencyBlock block; - - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(block = cbs->emergencyBlockList; - block != NULL && - (!found || CBSEmergencyBlockBase(block) < base); - block = CBSEmergencyBlockNext(block)) { - if (CBSEmergencyBlockSize(block) >= size) { - found = TRUE; - base = CBSEmergencyBlockBase(block); - limit = CBSEmergencyBlockLimit(block); - deleteMethod = &cbsDeleteFromEmergencyBlockList; - /* @@@@ Could remove in place more efficiently. */ - break; - } - } - } - - if (cbs->emergencyGrainList != NULL && - size <= CBSEmergencyGrainSize(cbs)) { - /* Take first grain */ - CBSEmergencyGrain grain = cbs->emergencyGrainList; - - if (!found || CBSEmergencyGrainBase(grain) < base) { - found = TRUE; - base = CBSEmergencyGrainBase(grain); - limit = CBSEmergencyGrainLimit(cbs, grain); - deleteMethod = &cbsDeleteFromEmergencyGrainList; - } - } - if (found) { AVER(AddrOffset(base, limit) >= size); cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size, @@ -1465,8 +938,6 @@ Bool CBSFindLast(Addr *baseReturn, Addr *limitReturn, AVER(cbs->fastFind); AVERT(CBSFindDelete, findDelete); - cbsFlushEmergencyLists(cbs); /* might do some good */ - { SplayNode node; @@ -1484,44 +955,6 @@ Bool CBSFindLast(Addr *baseReturn, Addr *limitReturn, } } - if (cbs->emergencyBlockList != NULL) { - CBSEmergencyBlock block; - - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(block = cbs->emergencyBlockList; - block != NULL; - block = CBSEmergencyBlockNext(block)) { - if (CBSEmergencyBlockSize(block) >= size && - (!found || CBSEmergencyBlockBase(block) > base)) { - found = TRUE; - base = CBSEmergencyBlockBase(block); - limit = CBSEmergencyBlockLimit(block); - deleteMethod = &cbsDeleteFromEmergencyBlockList; - /* @@@@ Could remove in place more efficiently. */ - } - } - } - - if (cbs->emergencyGrainList != NULL && - size <= CBSEmergencyGrainSize(cbs)) { - CBSEmergencyGrain grain; - - /* Find last grain */ - METER_ACC(cbs->eglSearch, cbs->eglSize); - for(grain = cbs->emergencyGrainList; - CBSEmergencyGrainNext(grain) != NULL; - grain = CBSEmergencyGrainNext(grain)) - NOOP; - - if (!found || CBSEmergencyGrainBase(grain) > base) { - found = TRUE; - base = CBSEmergencyGrainBase(grain); - limit = CBSEmergencyGrainLimit(cbs, grain); - deleteMethod = &cbsDeleteFromEmergencyGrainList; - /* @@@@ Could remove in place more efficiently */ - } - } - if (found) { AVER(AddrOffset(base, limit) >= size); cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size, @@ -1551,8 +984,6 @@ Bool CBSFindLargest(Addr *baseReturn, Addr *limitReturn, AVER(cbs->fastFind); AVERT(CBSFindDelete, findDelete); - cbsFlushEmergencyLists(cbs); /* might do some good */ - { SplayNode root; Bool notEmpty; @@ -1575,38 +1006,6 @@ Bool CBSFindLargest(Addr *baseReturn, Addr *limitReturn, } } - if (cbs->emergencyBlockList != NULL) { - CBSEmergencyBlock block; - - /* Scan the whole list -- could maintain a maxSize to avoid it. */ - METER_ACC(cbs->eblSearch, cbs->eblSize); - for(block = cbs->emergencyBlockList; - block != NULL; - block = CBSEmergencyBlockNext(block)) { - if (CBSEmergencyBlockSize(block) >= size) { - /* .pref: >= so that it prefers the emerg. list to the tree */ - found = TRUE; - size = CBSEmergencyBlockSize(block); - base = CBSEmergencyBlockBase(block); - limit = CBSEmergencyBlockLimit(block); - deleteMethod = &cbsDeleteFromEmergencyBlockList; - /* @@@@ Could remove in place more efficiently. */ - } - } - } - - /* If something was found, it will be larger than an emerg. grain. */ - if (!found && cbs->emergencyGrainList != NULL) { - /* Take first grain */ - CBSEmergencyGrain grain = cbs->emergencyGrainList; - - found = TRUE; - size = CBSEmergencyGrainSize(cbs); - base = CBSEmergencyGrainBase(grain); - limit = CBSEmergencyGrainLimit(cbs, grain); - deleteMethod = &cbsDeleteFromEmergencyGrainList; - } - if (found) { cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size, deleteMethod, findDelete); @@ -1642,10 +1041,6 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) res = METER_WRITE(cbs->splaySearch, stream); if (res != ResOK) return res; - res = METER_WRITE(cbs->eblSearch, stream); - if (res != ResOK) return res; - res = METER_WRITE(cbs->eglSearch, stream); - if (res != ResOK) return res; res = WriteF(stream, "}\n", NULL); return res; diff --git a/mps/code/cbs.h b/mps/code/cbs.h index b2fe4d0b27f..ddbda2343f3 100644 --- a/mps/code/cbs.h +++ b/mps/code/cbs.h @@ -21,13 +21,6 @@ typedef void (*CBSChangeSizeMethod)(CBS cbs, CBSBlock block, typedef Bool (*CBSIterateMethod)(CBS cbs, CBSBlock block, void *closureP); -/* See */ -typedef void **CBSEmergencyBlock; /* next, limit */ - -/* See */ -typedef void **CBSEmergencyGrain; /* next */ - - #define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */ typedef struct CBSStruct { @@ -40,17 +33,10 @@ typedef struct CBSStruct { CBSChangeSizeMethod shrink; Size minSize; Align alignment; - Bool mayUseInline; Bool fastFind; Bool inCBS; /* prevent reentrance */ - CBSEmergencyBlock emergencyBlockList; - Count eblSize; - CBSEmergencyGrain emergencyGrainList; - Count eglSize; /* meters for sizes of search structures at each op */ METER_DECL(splaySearch); - METER_DECL(eblSearch); - METER_DECL(eglSearch); Sig sig; /* sig at end because embeded */ } CBSStruct; @@ -72,7 +58,6 @@ extern Res CBSInit(Arena arena, CBS cbs, void *owner, CBSChangeSizeMethod shrink, Size minSize, Align alignment, - Bool mayUseInline, Bool fastFind); extern void CBSFinish(CBS cbs); diff --git a/mps/code/cbstest.c b/mps/code/cbstest.c index cb5744238dc..adb976081e2 100644 --- a/mps/code/cbstest.c +++ b/mps/code/cbstest.c @@ -591,7 +591,7 @@ extern int main(int argc, char *argv[]) die((mps_res_t)CBSInit(arena, &cbsStruct, NULL, &cbsNewCallback, &cbsDeleteCallback, &cbsGrowCallback, &cbsShrinkCallback, MinSize, - Alignment, TRUE, TRUE), + Alignment, TRUE), "failed to initialise CBS"); cbs = &cbsStruct; diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index dc10ce990a8..c99a0f0b225 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -237,7 +237,7 @@ static Res MVTInit(Pool pool, va_list arg) abqDepth = 3; res = CBSInit(arena, MVTCBS(mvt), (void *)mvt, &MVTNoteNew, &MVTNoteDelete, - NULL, NULL, reuseSize, MPS_PF_ALIGN, TRUE, FALSE); + NULL, NULL, reuseSize, MPS_PF_ALIGN, FALSE); if (res != ResOK) goto failCBS; diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index a2647608187..eea4e197911 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -466,7 +466,7 @@ static Res MVFFInit(Pool pool, va_list arg) mvff->free = 0; res = CBSInit(arena, CBSOfMVFF(mvff), (void *)mvff, NULL, NULL, NULL, NULL, - mvff->extendBy, align, TRUE, TRUE); + mvff->extendBy, align, TRUE); if (res != ResOK) goto failInit; @@ -686,8 +686,8 @@ void mps_mvff_stat(mps_pool_t mps_pool) AVERT(MVFF, mvff); METER_EMIT(&CBSOfMVFF(mvff)->splaySearch); - METER_EMIT(&CBSOfMVFF(mvff)->eblSearch); - METER_EMIT(&CBSOfMVFF(mvff)->eglSearch); + /* FIXME: METER_EMIT(&CBSOfMVFF(mvff)->eblSearch); */ + /* FIXME: METER_EMIT(&CBSOfMVFF(mvff)->eglSearch); */ } diff --git a/mps/design/cbs.rst b/mps/design/cbs.rst index 63f7356605a..21a664233d3 100644 --- a/mps/design/cbs.rst +++ b/mps/design/cbs.rst @@ -456,53 +456,18 @@ the largest block in the CBS from the root of the tree (using ``SplayRoot``), and does ``SplayFindFirst`` for a block of that size. This is O(log(*n*)) in the size of the free list, so it's about the best you can do without maintaining a separate priority queue, just to -do ``CBSFindLargest``. Except when the emergency lists (see -`.impl.low-mem`_) are in use, they are also searched. +do ``CBSFindLargest``. Low memory behaviour .................... -_`impl.low-mem`: Low memory situations cause problems when the CBS -tries to allocate a new ``CBSBlock`` structure for a new isolated -range as a result of either ``CBSInsert`` or ``CBSDelete``, and there -is insufficient memory to allocation the ``CBSBlock`` structure: - -_`impl.low-mem.no-inline`: If ``mayUseInline`` is ``FALSE``, then the -range is not added to the CBS, and the call to ``CBSInsert`` or -``CBSDelete`` returns ``ResMEMORY``. - -_`impl.low-mem.inline`: If ``mayUseInline`` is ``TRUE``: - -_`impl.low-mem.inline.block`: If the range is large enough to contain -an inline block descriptor consisting of two pointers, then it is kept -on an emergency block list. The CBS will eagerly attempt to add this -block back into the splay tree during subsequent calls to -``CBSInsert`` and ``CBSDelete``. The CBS will also keep its emergency -block list in address order, and will coalesce this list eagerly. Some -performance degradation will be seen when the emergency block list is -in use. Ranges on this emergency block list will not be made available -to the CBS's client via callbacks. ``CBSIterate`` and -``CBSIterateLarge`` will not iterate over ranges on this list. - -_`impl.low-mem.inline.block.structure`: The two pointers stored are to -the next such block (or ``NULL``), and to the limit of the block, in -that order. - -_`impl.low-mem.inline.grain`: Otherwise, the range must be large -enough to contain an inline grain descriptor consisting of one -pointer, then it is kept on an emergency grain list. The CBS will -eagerly attempt to add this grain back into either the splay tree or -the emergency block list during subsequent calls to ``CBSInsert`` and -``CBSDelete``. The CBS will also keep its emergency grain list in -address order. Some performance degradation will be seen when the -emergency grain list is in use. Ranges on this emergency grain list -will not be made available to the CBS's client via callbacks. -``CBSIterate`` and ``CBSIterateLarge`` will not iterate over ranges on -this list. - -_`impl.low-mem.inline.grain.structure`: The pointer stored is to the -next such grain, or ``NULL``. +_`impl.low-mem`: When the CBS tries to allocate a new ``CBSBlock`` +structure for a new isolated range as a result of either ``CBSInsert`` +or ``CBSDelete``, and there is insufficient memory to allocation the +``CBSBlock`` structure, then the range is not added to the CBS or +deleted from it, and the call to ``CBSInsert`` or ``CBSDelete`` +returns ``ResMEMORY``. The CBS block @@ -562,112 +527,10 @@ _`risk.overhead`: Clients should note that the current implementation of CBSs has a space overhead proportional to the number of isolated contiguous ranges. [Four words per range.] If the CBS contains every other grain in an area, then the overhead will be large compared to -the size of that area. [Four words per two grains.] See -`.future.hybrid`_ for a suggestion to solve this problem. An -alternative solution is to use CBSs only for managing long ranges. +the size of that area. [Four words per two grains.] The CBS structure +is thus suitable only for managing large enough ranges. -Proposed hybrid implementation ------------------------------- - -.. note:: - - The following relates to a pending re-design and does not yet - relate to any working source version. GavinM 1998-09-25 - -The CBS system provides its services by combining the services -provided by three subsidiary CBS modules: - -- ``CBSST`` -- Splay Tree: Based on out-of-line splay trees; must - allocate to insert isolated, which may therefore fail. - -- ``CBSBL`` -- Block List: Based on a singly-linked list of variable - sized ranges with inline descriptors; ranges must be at least large - enough to store the inline descriptor. - -- ``CBSGL`` -- Grain List: Based on a singly-linked list of fixed size - ranges with inline descriptors; the ranges must be the alignment of - the CBS. - -The three sub-modules have a lot in common. Although their methods are -not invoked via a dispatcher, they have been given consistent -interfaces, and consistent internal appearance, to aid maintenance. - -Methods supported by sub-modules (not all sub-modules support all -methods): - -- ``MergeRange`` -- Finds any ranges in the specific CBS adjacent to - the supplied one. If there are any, it extends the ranges, possibly - deleting one of them. This cannot fail, but should return ``FALSE`` - if there is an intersection between the supplied range and a range - in the specific CBS. - -- ``InsertIsolatedRange`` -- Adds a range to the specific CBS that is - not adjacent to any range already in there. Depending on the - specific CBS, this may be able to fail for allocation reasons, in - which case it should return ``FALSE``. It should ``AVER`` if the - range is adjacent to or intersects with a range already there. - -- ``RemoveAdjacentRanges`` -- Finds and removes from the specific CBS - any ranges that are adjacent to the supplied range. Should return - ``FALSE`` if the supplied range intersects with any ranges already - there. - -- ``DeleteRange`` -- Finds and deletes the supplied range from the - specific CBS. Returns a tri-state result: - - - ``Success`` -- The range was successfully deleted. This may have - involved the creation of a new range, which should be done via - ``CBSInsertIsolatedRange``. - - - ``ProtocolError`` -- Either some non-trivial strict subset of the - supplied range was in the specific CBS, or a range adjacent to the - supplied range was in the specific CBS. Either of these indicates - a protocol error. - - - ``NoIntersection`` -- The supplied range was not found in the CBS. - This may or not be a protocol error, depending on the invocation - context. - -- ``FindFirst`` -- Returns the first (in address order) range in the - specific CBS that is at least as large as the supplied size, or - ``FALSE`` if there is no such range. - -- ``FindFirstBefore`` -- As ``FindFirst``, but only finds ranges prior - to the supplied address. - -- ``FindLast`` -- As ``FindFirst``, but finds the last such range in - address order. - -- ``FindLastAfter`` -- ``FindLast`` equivalent of ``FindFirstBefore``. - -- ``Init`` -- Initialise the control structure embedded in the CBS. - -- ``Finish`` -- Finish the control structure embedded in the CBS. - -- ``InlineDescriptorSize`` -- Returns the aligned size of the inline - descriptor. - -- ``Check`` -- Checks the control structure embedded in the CBS. - -The CBS supplies the following utilities: - -- ``CBSAlignment`` -- Returns the alignment of the CBS. - -- ``CBSMayUseInline`` -- Returns whether the CBS may use the memory in - the ranges stored. - -- ``CBSInsertIsolatedRange`` -- Wrapper for ``CBS*InsertIsolatedRange``. - -Internally, the ``CBS*`` sub-modules each have an internal structure -``CBS*Block`` that represents an isolated range within the module. It -supports the following methods (for sub-module internal use): - -- ``BlockBase`` -- Returns the base of the associated range; -- ``BlockLimit`` -- ``BlockRange`` -- ``BlockSize`` - B. Document history ------------------- @@ -687,6 +550,9 @@ B. Document history - 2013-04-14 GDR_ Converted to reStructuredText. +- 2013-05-19 GDR_ Remove the "emergency" free list allocator and the + design notes on an unimplemented "future hybrid" scheme. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/