/* AMSAllocateRange -- set a range to be allocated * * Used as a means of overriding the behaviour of AMSBufferFill. * The code is similar to AMSUnallocateRange. */ static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit) { AMSSeg amsseg; Index baseIndex, limitIndex; Count allocatedGrains; /* parameters checked by caller */ amsseg = Seg2AMSSeg(seg); baseIndex = PoolIndexOfAddr(SegBase(seg), SegPool(seg), base); limitIndex = PoolIndexOfAddr(SegBase(seg), SegPool(seg), limit); if (amsseg->allocTableInUse) { /* check that it's not allocated */ AVER(BTIsResRange(amsseg->allocTable, baseIndex, limitIndex)); BTSetRange(amsseg->allocTable, baseIndex, limitIndex); } else { /* check that it's not allocated */ AVER(baseIndex >= amsseg->firstFree); if (baseIndex == amsseg->firstFree) /* is it at the end? */ { amsseg->firstFree = limitIndex; } else { /* start using allocTable */ amsseg->allocTableInUse = TRUE; BTSetRange(amsseg->allocTable, 0, amsseg->firstFree); if (amsseg->firstFree < amsseg->grains) BTResRange(amsseg->allocTable, amsseg->firstFree, amsseg->grains); BTSetRange(amsseg->allocTable, baseIndex, limitIndex); } } allocatedGrains = limitIndex - baseIndex; AVER(amsseg->freeGrains >= allocatedGrains); amsseg->freeGrains -= allocatedGrains; amsseg->bufferedGrains += allocatedGrains; PoolGenAccountForFill(ams->pgen, AddrOffset(base, limit)); }
static void test(FBMState state, unsigned n) { Addr base, limit; unsigned i; Size size; Bool high; FindDelete findDelete = FindDeleteNONE; BTSetRange(state->allocTable, 0, ArraySize); /* Initially all allocated */ check(state); for(i = 0; i < n; i++) { switch(fbmRnd(3)) { case 0: randomRange(&base, &limit, state); allocate(state, base, limit); break; case 1: randomRange(&base, &limit, state); deallocate(state, base, limit); break; case 2: size = fbmRnd(ArraySize / 10) + 1; high = fbmRnd(2) ? TRUE : FALSE; switch(fbmRnd(6)) { case 0: case 1: case 2: findDelete = FindDeleteNONE; break; case 3: findDelete = FindDeleteLOW; break; case 4: findDelete = FindDeleteHIGH; break; case 5: findDelete = FindDeleteENTIRE; break; } find(state, size, high, findDelete); break; default: fail(); return; } if ((i + 1) % 1000 == 0) check(state); } }
/* AMSUnallocateRange -- set a range to be unallocated * * Used as a means of overriding the behaviour of AMSBufferFill. * The code is similar to amsSegBufferEmpty. */ static void AMSUnallocateRange(AMS ams, Seg seg, Addr base, Addr limit) { AMSSeg amsseg; Index baseIndex, limitIndex; Count unallocatedGrains; /* parameters checked by caller */ amsseg = Seg2AMSSeg(seg); baseIndex = PoolIndexOfAddr(SegBase(seg), SegPool(seg), base); limitIndex = PoolIndexOfAddr(SegBase(seg), SegPool(seg), limit); if (amsseg->allocTableInUse) { /* check that it's allocated */ AVER(BTIsSetRange(amsseg->allocTable, baseIndex, limitIndex)); BTResRange(amsseg->allocTable, baseIndex, limitIndex); } else { /* check that it's allocated */ AVER(limitIndex <= amsseg->firstFree); if (limitIndex == amsseg->firstFree) /* is it at the end? */ { amsseg->firstFree = baseIndex; } else { /* start using allocTable */ amsseg->allocTableInUse = TRUE; BTSetRange(amsseg->allocTable, 0, amsseg->firstFree); if (amsseg->firstFree < amsseg->grains) BTResRange(amsseg->allocTable, amsseg->firstFree, amsseg->grains); BTResRange(amsseg->allocTable, baseIndex, limitIndex); } } unallocatedGrains = limitIndex - baseIndex; AVER(amsseg->bufferedGrains >= unallocatedGrains); amsseg->freeGrains += unallocatedGrains; amsseg->bufferedGrains -= unallocatedGrains; PoolGenAccountForEmpty(ams->pgen, 0, PoolGrainsSize(AMSPool(ams), unallocatedGrains), FALSE); }
static void setRange(void) { if (checkDefaultRange(0)) BTSetRange(bt, args[0], args[1]); }
static void find(FBMState state, Size size, Bool high, FindDelete findDelete) { Bool expected, found; Index expectedBase, expectedLimit; RangeStruct foundRange, oldRange; Addr remainderBase, remainderLimit; Addr origBase, origLimit; Size oldSize, newSize; origBase = origLimit = NULL; expected = (high ? BTFindLongResRangeHigh : BTFindLongResRange) (&expectedBase, &expectedLimit, state->allocTable, (Index)0, (Index)ArraySize, (Count)size); if (expected) { oldSize = (expectedLimit - expectedBase) * state->align; remainderBase = origBase = addrOfIndex(state, expectedBase); remainderLimit = origLimit = addrOfIndex(state, expectedLimit); switch(findDelete) { case FindDeleteNONE: { /* do nothing */ } break; case FindDeleteENTIRE: { remainderBase = remainderLimit; } break; case FindDeleteLOW: { expectedLimit = expectedBase + size; remainderBase = addrOfIndex(state, expectedLimit); } break; case FindDeleteHIGH: { expectedBase = expectedLimit - size; remainderLimit = addrOfIndex(state, expectedBase); } break; } if (findDelete != FindDeleteNONE) { newSize = AddrOffset(remainderBase, remainderLimit); } /* TODO: check these values */ UNUSED(oldSize); UNUSED(newSize); } switch (state->type) { case FBMTypeCBS: found = (high ? CBSFindLast : CBSFindFirst) (&foundRange, &oldRange, state->the.cbs, size * state->align, findDelete); break; case FBMTypeFreelist: found = (high ? FreelistFindLast : FreelistFindFirst) (&foundRange, &oldRange, state->the.fl, size * state->align, findDelete); break; default: fail(); return; } if (verbose) { printf("find %s %lu: ", high ? "last" : "first", (unsigned long)(size * state->align)); if (expected) { printf("expecting [%p,%p)\n", (void *)addrOfIndex(state, expectedBase), (void *)addrOfIndex(state, expectedLimit)); } else { printf("expecting this not to be found\n"); } if (found) { printf(" found [%p,%p)\n", (void *)RangeBase(&foundRange), (void *)RangeLimit(&foundRange)); } else { printf(" not found\n"); } } Insist(found == expected); if (found) { Insist(expectedBase == indexOfAddr(state, RangeBase(&foundRange))); Insist(expectedLimit == indexOfAddr(state, RangeLimit(&foundRange))); if (findDelete != FindDeleteNONE) { Insist(RangeBase(&oldRange) == origBase); Insist(RangeLimit(&oldRange) == origLimit); BTSetRange(state->allocTable, expectedBase, expectedLimit); } } return; }
static void allocate(FBMState state, Addr base, Addr limit) { Res res; Index ib, il; /* Indexed for base and limit */ Bool isFree; RangeStruct range, oldRange; Addr outerBase, outerLimit; /* interval containing [ib, il) */ ib = indexOfAddr(state, base); il = indexOfAddr(state, limit); isFree = BTIsResRange(state->allocTable, ib, il); NAllocateTried++; if (isFree) { Size left, right, total; /* Sizes of block and two fragments */ outerBase = addrOfIndex(state, lastEdge(state->allocTable, ArraySize, ib)); outerLimit = addrOfIndex(state, nextEdge(state->allocTable, ArraySize, il - 1)); left = AddrOffset(outerBase, base); right = AddrOffset(limit, outerLimit); total = AddrOffset(outerBase, outerLimit); /* TODO: check these values */ UNUSED(left); UNUSED(right); UNUSED(total); } else { outerBase = outerLimit = NULL; } RangeInit(&range, base, limit); switch (state->type) { case FBMTypeCBS: res = CBSDelete(&oldRange, state->the.cbs, &range); break; case FBMTypeFreelist: res = FreelistDelete(&oldRange, state->the.fl, &range); break; default: fail(); return; } if (verbose) { printf("allocate: [%p,%p) -- %s\n", (void *)base, (void *)limit, isFree ? "succeed" : "fail"); describe(state); } if (!isFree) { die_expect((mps_res_t)res, MPS_RES_FAIL, "Succeeded in deleting allocated block"); } else { /* isFree */ die_expect((mps_res_t)res, MPS_RES_OK, "failed to delete free block"); Insist(RangeBase(&oldRange) == outerBase); Insist(RangeLimit(&oldRange) == outerLimit); NAllocateSucceeded++; BTSetRange(state->allocTable, ib, il); } }
extern int main(int argc, char *argv[]) { unsigned i; Addr base, limit; mps_arena_t mpsArena; Arena arena; /* the ANSI arena which we use to allocate the BT */ CBSStruct cbsStruct; CBS cbs; void *p; Addr dummyBlock; BT allocTable; Size size; Bool high; CBSFindDelete findDelete = CBSFindDeleteNONE; randomize(argc, argv); NAllocateTried = NAllocateSucceeded = NDeallocateTried = NDeallocateSucceeded = NNewBlocks = NDeleteBlocks = NGrowBlocks = NShrinkBlocks = 0; clearExpectations(); die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE), "mps_arena_create"); arena = (Arena)mpsArena; /* avoid pun */ die((mps_res_t)BTCreate(&allocTable, arena, ArraySize), "failed to create alloc table"); die((mps_res_t)CBSInit(arena, &cbsStruct, NULL, &cbsNewCallback, &cbsDeleteCallback, &cbsGrowCallback, &cbsShrinkCallback, MinSize, Alignment, TRUE, TRUE), "failed to initialise CBS"); cbs = &cbsStruct; BTSetRange(allocTable, 0, ArraySize); /* Initially all allocated */ /* We're not going to use this block, but I feel unhappy just */ /* inventing addresses. */ die((mps_res_t)ControlAlloc(&p, arena, ArraySize * Alignment, /* withReservoirPermit */ FALSE), "failed to allocate block"); dummyBlock = (Addr)p; /* avoid pun */ printf("Allocated block [%p, %p)\n", (void*)dummyBlock, (char *)dummyBlock + ArraySize); checkCBS(cbs, allocTable, dummyBlock); for(i = 0; i < NOperations; i++) { switch(cbsRnd(3)) { case 0: { randomRange(&base, &limit, allocTable, dummyBlock); allocate(cbs, dummyBlock, allocTable, base, limit); } break; case 1: { randomRange(&base, &limit, allocTable, dummyBlock); deallocate(cbs, dummyBlock, allocTable, base, limit); } break; case 2: { size = cbsRnd(ArraySize / 10) + 1; high = cbsRnd(2) ? TRUE : FALSE; switch(cbsRnd(6)) { case 0: case 1: case 2: findDelete = CBSFindDeleteNONE; break; case 3: findDelete = CBSFindDeleteLOW; break; case 4: findDelete = CBSFindDeleteHIGH; break; case 5: findDelete = CBSFindDeleteENTIRE; break; } find(cbs, dummyBlock, allocTable, size, high, findDelete); } break; } if (i % 5000 == 0) checkCBS(cbs, allocTable, dummyBlock); } checkExpectations(); /* CBSDescribe prints a very long line. */ /* CBSDescribe(cbs, mps_lib_get_stdout()); */ printf("\nNumber of allocations attempted: %ld\n", NAllocateTried); printf("Number of allocations succeeded: %ld\n", NAllocateSucceeded); printf("Number of deallocations attempted: %ld\n", NDeallocateTried); printf("Number of deallocations succeeded: %ld\n", NDeallocateSucceeded); printf("Number of new large blocks: %ld\n", NNewBlocks); printf("Number of deleted large blocks: %ld\n", NDeleteBlocks); printf("Number of grown large blocks: %ld\n", NGrowBlocks); printf("Number of shrunk large blocks: %ld\n", NShrinkBlocks); printf("\nNo problems detected.\n"); return 0; }
static void find(CBS cbs, void *block, BT alloc, Size size, Bool high, CBSFindDelete findDelete) { Bool expected, found; Index expectedBase, expectedLimit; Addr foundBase, foundLimit, remainderBase, remainderLimit; Size oldSize, newSize; checkExpectations(); expected = (high ? BTFindLongResRangeHigh : BTFindLongResRange) (&expectedBase, &expectedLimit, alloc, (Index)0, (Index)ArraySize, (Count)size); if (expected) { oldSize = (expectedLimit - expectedBase) * Alignment; remainderBase = addrOfIndex(block, expectedBase); remainderLimit = addrOfIndex(block, expectedLimit); switch(findDelete) { case CBSFindDeleteNONE: { /* do nothing */ } break; case CBSFindDeleteENTIRE: { remainderBase = remainderLimit; } break; case CBSFindDeleteLOW: { expectedLimit = expectedBase + size; remainderBase = addrOfIndex(block, expectedLimit); } break; case CBSFindDeleteHIGH: { expectedBase = expectedLimit - size; remainderLimit = addrOfIndex(block, expectedBase); } break; } if (findDelete != CBSFindDeleteNONE) { newSize = AddrOffset(remainderBase, remainderLimit); if (oldSize >= MinSize) { if (newSize == 0) expectCallback(&CallbackDelete, oldSize, (Addr)0, (Addr)0); else if (newSize < MinSize) expectCallback(&CallbackDelete, oldSize, remainderBase, remainderLimit); else expectCallback(&CallbackShrink, oldSize, remainderBase, remainderLimit); } } } found = (high ? CBSFindLast : CBSFindFirst) (&foundBase, &foundLimit, cbs, size * Alignment, findDelete); Insist(found == expected); if (found) { Insist(expectedBase == indexOfAddr(block, foundBase)); Insist(expectedLimit == indexOfAddr(block, foundLimit)); checkExpectations(); if (findDelete != CBSFindDeleteNONE) BTSetRange(alloc, expectedBase, expectedLimit); } return; }
static void allocate(CBS cbs, Addr block, BT allocTable, Addr base, Addr limit) { Res res; Index ib, il; /* Indexed for base and limit */ Bool isFree; ib = indexOfAddr(block, base); il = indexOfAddr(block, limit); isFree = BTIsResRange(allocTable, ib, il); /* printf("allocate: [%p, %p) -- %s\n", base, limit, isFree ? "succeed" : "fail"); */ NAllocateTried++; if (isFree) { Addr outerBase, outerLimit; /* interval containing [ib, il) */ Size left, right, total; /* Sizes of block and two fragments */ outerBase = addrOfIndex(block, lastEdge(allocTable, ArraySize, ib)); outerLimit = addrOfIndex(block, nextEdge(allocTable, ArraySize, il - 1)); left = AddrOffset(outerBase, base); right = AddrOffset(limit, outerLimit); total = AddrOffset(outerBase, outerLimit); /* based on detailed knowledge of CBS behaviour */ checkExpectations(); if (total >= MinSize && left < MinSize && right < MinSize) { if (left == (Size)0 && right == (Size)0) { expectCallback(&CallbackDelete, total, (Addr)0, (Addr)0); } else if (left >= right) { expectCallback(&CallbackDelete, total, outerBase, base); } else { expectCallback(&CallbackDelete, total, limit, outerLimit); } } else if (left >= MinSize && right >= MinSize) { if (left >= right) { expectCallback(&CallbackShrink, total, outerBase, base); expectCallback(&CallbackNew, (Size)0, limit, outerLimit); } else { expectCallback(&CallbackNew, (Size)0, outerBase, base); expectCallback(&CallbackShrink, total, limit, outerLimit); } } else if (total >= MinSize) { if (left >= right) { Insist(left >= MinSize); Insist(right < MinSize); expectCallback(&CallbackShrink, total, outerBase, base); } else { Insist(left < MinSize); Insist(right >= MinSize); expectCallback(&CallbackShrink, total, limit, outerLimit); } } } res = CBSDelete(cbs, base, limit); if (!isFree) { die_expect((mps_res_t)res, MPS_RES_FAIL, "Succeeded in deleting allocated block"); } else { /* isFree */ die_expect((mps_res_t)res, MPS_RES_OK, "failed to delete free block"); NAllocateSucceeded++; BTSetRange(allocTable, ib, il); checkExpectations(); } }