From 4cca37c61cfafbaaa3aa5c87629a2ab5fdbbf277 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 14:45:51 +0100 Subject: [PATCH 1/8] Branching master to branch/2014-04-22/condemn. Copied from Perforce Change: 185735 ServerID: perforce.ravenbrook.com From e7d41a8fdeae24d55b46364563f60bdc79d7355c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 17:53:47 +0100 Subject: [PATCH 2/8] Fix bugs in condemn logic: 1. TraceStartCollectAll now condemns all segments in pools with AttrGC (not just pools attached to generation zero of some chain, as before). 2. ChainDeferral now looks at all generations in the chain, so that the chain is condemned if any generation's new size is greater than its capacity (not just generation zero, as before). 3. ChainCondemnAuto now condemns all generations up to and including the highest generation whose new size is greater than its capacity (rather than, as before, up to and excluding the lowest generation whose new size is lower than its capacity). Update finaltest.c so that it has a mode in which it allocates in generation 1 of a chain and with the arena released so that the above fixes are tested. Remove the MPS_KEY_GEN workarounds from awlut and awluthe as these are no longer needed. Copied from Perforce Change: 185741 ServerID: perforce.ravenbrook.com --- mps/code/awlut.c | 3 -- mps/code/awluthe.c | 3 -- mps/code/chain.h | 1 - mps/code/finaltest.c | 104 +++++++++++++++++++++++++++++++++---------- mps/code/locus.c | 100 +++++++++++++++++------------------------ mps/code/trace.c | 28 ++++++++---- 6 files changed, 140 insertions(+), 99 deletions(-) diff --git a/mps/code/awlut.c b/mps/code/awlut.c index c62153ed44c..464a2dba91f 100644 --- a/mps/code/awlut.c +++ b/mps/code/awlut.c @@ -275,9 +275,6 @@ static void *setup(void *v, size_t s) die(mps_fmt_create_A(&dylanweakfmt, arena, dylan_fmt_A_weak()), "Format Create (weak)\n"); MPS_ARGS_BEGIN(args) { - /* Ask the leafpool to allocate in the nursery, as we're using it to test - weaknesss and want things to die in it promptly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, dylanfmt); die(mps_pool_create_k(&leafpool, arena, mps_class_lo(), args), "Leaf Pool Create\n"); diff --git a/mps/code/awluthe.c b/mps/code/awluthe.c index d3b2d572319..6ea468977f1 100644 --- a/mps/code/awluthe.c +++ b/mps/code/awluthe.c @@ -277,9 +277,6 @@ static void *setup(void *v, size_t s) die(EnsureHeaderFormat(&dylanfmt, arena), "EnsureHeaderFormat"); die(EnsureHeaderWeakFormat(&dylanweakfmt, arena), "EnsureHeaderWeakFormat"); MPS_ARGS_BEGIN(args) { - /* Ask the leafpool to allocate in the nursery, as we're using it to test - weaknesss and want things to die in it promptly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, dylanfmt); die(mps_pool_create_k(&leafpool, arena, mps_class_lo(), args), "Leaf Pool Create\n"); diff --git a/mps/code/chain.h b/mps/code/chain.h index e47f8000c0b..ec5bc228ebf 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -81,7 +81,6 @@ extern Bool ChainCheck(Chain chain); extern double ChainDeferral(Chain chain); extern Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace); -extern Res ChainCondemnAll(Chain chain, Trace trace); extern void ChainStartGC(Chain chain, Trace trace); extern void ChainEndGC(Chain chain, Trace trace); extern size_t ChainGens(Chain chain); diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index 88895027286..a9580bfcbdf 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -6,6 +6,20 @@ * * DESIGN * + * .mode: This test has two modes. + * + * .mode.park: In this mode, we use the arena's default generation + * chain, leave the arena parked and call mps_arena_collect. This + * tests that the default generation chain works and that all segments + * get condemned via TraceStartCollectAll. (See job003771 item 4.) + * + * .mode.poll: In this mode, we use our own generation chain (with + * small generations), allocate into generation 1, unclamp the arena, + * and provoke collection by allocating. This tests that custom + * generation chains work, and that segments get condemned via + * TracePoll even if there is no allocation into generation 0 of the + * chain. (See job003771 item 5.) + * * DEPENDENCIES * * This test uses the dylan object format, but the reliance on this @@ -16,6 +30,7 @@ * This code was created by first copying */ +#include "mpm.h" #include "testlib.h" #include "mpslib.h" #include "mps.h" @@ -30,10 +45,15 @@ #include /* fflush, printf, stdout */ +enum { + ModePARK, /* .mode.park */ + ModePOLL /* .mode.poll */ +}; + #define testArenaSIZE ((size_t)16<<20) #define rootCOUNT 20 -#define maxtreeDEPTH 10 +#define maxtreeDEPTH 9 #define collectionCOUNT 10 @@ -126,17 +146,21 @@ static mps_addr_t test_awl_find_dependent(mps_addr_t addr) static void *root[rootCOUNT]; -static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, +static void test_trees(int mode, const char *name, mps_arena_t arena, + mps_ap_t ap, mps_word_t (*make)(mps_word_t, mps_ap_t), void (*reg)(mps_word_t, mps_arena_t)) { size_t collections = 0; size_t finals = 0; size_t i; + int object_alloc; object_count = 0; printf("Making some %s finalized trees of objects.\n", name); + mps_arena_park(arena); + /* make some trees */ for(i = 0; i < rootCOUNT; ++i) { root[i] = (void *)(*make)(maxtreeDEPTH, ap); @@ -151,10 +175,23 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, while (finals < object_count && collections < collectionCOUNT) { mps_word_t final_this_time = 0; - printf("Collecting..."); - (void)fflush(stdout); - die(mps_arena_collect(arena), "collect"); - printf(" Done.\n"); + switch (mode) { + default: + case ModePARK: + printf("Collecting..."); + (void)fflush(stdout); + die(mps_arena_collect(arena), "collect"); + printf(" Done.\n"); + break; + case ModePOLL: + mps_arena_release(arena); + printf("Allocating..."); + (void)fflush(stdout); + object_alloc = 0; + while (object_alloc < 1000 && !mps_message_poll(arena)) + (void)DYLAN_INT(object_alloc++); + break; + } ++ collections; while (mps_message_poll(arena)) { mps_message_t message; @@ -170,10 +207,14 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap, " of %"PRIuLONGEST"\n", (ulongest_t)final_this_time, (ulongest_t)finals, (ulongest_t)object_count); } - cdie(finals == object_count, "Not all objects were finalized."); + if (finals != object_count) + error("Not all objects were finalized for %s in mode %s.", + BufferOfAP(ap)->pool->class->name, + mode == ModePOLL ? "POLL" : "PARK"); } -static void *test(mps_arena_t arena, mps_class_t pool_class) +static void test_pool(int mode, mps_arena_t arena, mps_chain_t chain, + mps_class_t pool_class) { mps_ap_t ap; mps_fmt_t fmt; @@ -182,10 +223,13 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n"); MPS_ARGS_BEGIN(args) { - /* Allocate into generation 0 so that they get finalized quickly. */ - MPS_ARGS_ADD(args, MPS_KEY_GEN, 0); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); - MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent); + if (mode == ModePOLL) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_GEN, 1); + } + if (pool_class == mps_class_awl()) + MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent); die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n"); } MPS_ARGS_END(args); @@ -194,19 +238,25 @@ static void *test(mps_arena_t arena, mps_class_t pool_class) "root_create\n"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n"); - mps_message_type_enable(arena, mps_message_type_finalization()); - - mps_arena_park(arena); - - test_trees("numbered", arena, ap, make_numbered_tree, register_numbered_tree); - test_trees("indirect", arena, ap, make_indirect_tree, register_indirect_tree); + test_trees(mode, "numbered", arena, ap, make_numbered_tree, + register_numbered_tree); + test_trees(mode, "indirect", arena, ap, make_indirect_tree, + register_indirect_tree); mps_ap_destroy(ap); mps_root_destroy(mps_root); mps_pool_destroy(pool); mps_fmt_destroy(fmt); +} - return NULL; + +static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain) +{ + test_pool(mode, arena, chain, mps_class_amc()); + test_pool(mode, arena, chain, mps_class_amcz()); + test_pool(mode, arena, chain, mps_class_ams()); + /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003772 */ + /* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */ } @@ -214,19 +264,27 @@ int main(int argc, char *argv[]) { mps_arena_t arena; mps_thr_t thread; + mps_chain_t chain; + mps_gen_param_s params[2]; + size_t gens = 2; + size_t i; testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create\n"); + mps_message_type_enable(arena, mps_message_type_finalization()); die(mps_thread_reg(&thread, arena), "thread_reg\n"); + for (i = 0; i < gens; ++i) { + params[i].mps_capacity = 1; + params[i].mps_mortality = 0.5; + } + die(mps_chain_create(&chain, arena, gens, params), "chain_create\n"); - test(arena, mps_class_amc()); - test(arena, mps_class_amcz()); - test(arena, mps_class_ams()); - test(arena, mps_class_awl()); - /* TODO: test(arena, mps_class_lo()); */ + test_mode(ModePOLL, arena, chain); + test_mode(ModePARK, arena, NULL); + mps_chain_destroy(chain); mps_thread_dereg(thread); mps_arena_destroy(arena); diff --git a/mps/code/locus.c b/mps/code/locus.c index a704c8b820b..e69b276ab93 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -287,13 +287,20 @@ Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, SegClass class, double ChainDeferral(Chain chain) { + double time = DBL_MAX; + size_t i; + AVERT(Chain, chain); - if (chain->activeTraces != TraceSetEMPTY) - return DBL_MAX; - else - return chain->gens[0].capacity * 1024.0 - - (double)GenDescNewSize(&chain->gens[0]); + if (chain->activeTraces == TraceSetEMPTY) + for (i = 0; i < chain->genCount; ++i) { + double genTime = chain->gens[i].capacity * 1024.0 + - (double)GenDescNewSize(&chain->gens[i]); + if (genTime < time) + time = genTime; + } + + return time; } @@ -306,7 +313,7 @@ double ChainDeferral(Chain chain) Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) { Res res; - Serial topCondemnedGenSerial, currGenSerial; + size_t topCondemnedGen, i; GenDesc gen; ZoneSet condemnedSet = ZoneSetEMPTY; Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize; @@ -314,33 +321,39 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) AVERT(Chain, chain); AVERT(Trace, trace); - /* Find lowest gen within its capacity, set topCondemnedGenSerial to the */ - /* preceeding one. */ - currGenSerial = 0; - gen = &chain->gens[0]; - AVERT(GenDesc, gen); - genNewSize = GenDescNewSize(gen); - do { /* At this point, we've decided to collect currGenSerial. */ - topCondemnedGenSerial = currGenSerial; + /* Find the highest generation that's over capacity. We will condemn + * this and all lower generations in the chain. */ + topCondemnedGen = chain->genCount; + for (;;) { + /* It's an error to call this function unless some generation is + * over capacity as reported by ChainDeferral. */ + AVER(topCondemnedGen > 0); + if (topCondemnedGen == 0) + return ResFAIL; + -- topCondemnedGen; + gen = &chain->gens[topCondemnedGen]; + AVERT(GenDesc, gen); + genNewSize = GenDescNewSize(gen); + if (genNewSize >= gen->capacity * (Size)1024) + break; + } + + /* At this point, we've decided to condemn topCondemnedGen and all + * lower generations. */ + for (i = 0; i <= topCondemnedGen; ++i) { + gen = &chain->gens[i]; + AVERT(GenDesc, gen); condemnedSet = ZoneSetUnion(condemnedSet, gen->zones); genTotalSize = GenDescTotalSize(gen); + genNewSize = GenDescNewSize(gen); condemnedSize += genTotalSize; survivorSize += (Size)(genNewSize * (1.0 - gen->mortality)) /* predict survivors will survive again */ + (genTotalSize - genNewSize); - - /* is there another one to consider? */ - currGenSerial += 1; - if (currGenSerial >= chain->genCount) - break; /* reached the top */ - gen = &chain->gens[currGenSerial]; - AVERT(GenDesc, gen); - genNewSize = GenDescNewSize(gen); - } while (genNewSize >= gen->capacity * (Size)1024); + } AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0); - EVENT3(ChainCondemnAuto, chain, topCondemnedGenSerial, chain->genCount); - UNUSED(topCondemnedGenSerial); /* only used for EVENT */ + EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount); /* Condemn everything in these zones. */ if (condemnedSet != ZoneSetEMPTY) { @@ -354,41 +367,6 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) } -/* ChainCondemnAll -- condemn everything in the chain */ - -Res ChainCondemnAll(Chain chain, Trace trace) -{ - Ring node, nextNode; - Bool haveWhiteSegs = FALSE; - Res res; - - /* Condemn every segment in every pool using this chain. */ - /* Finds the pools by iterating over the PoolGens in gen 0. */ - RING_FOR(node, &chain->gens[0].locusRing, nextNode) { - PoolGen nursery = RING_ELT(PoolGen, genRing, node); - Pool pool = nursery->pool; - Ring segNode, nextSegNode; - - AVERT(Pool, pool); - AVER(PoolHasAttr(pool, AttrGC)); - RING_FOR(segNode, PoolSegRing(pool), nextSegNode) { - Seg seg = SegOfPoolRing(segNode); - - res = TraceAddWhite(trace, seg); - if (res != ResOK) - goto failBegin; - haveWhiteSegs = TRUE; - } - } - - return ResOK; - -failBegin: - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ - return res; -} - - /* ChainStartGC -- called to notify start of GC for this chain */ void ChainStartGC(Chain chain, Trace trace) @@ -416,9 +394,11 @@ void ChainEndGC(Chain chain, Trace trace) Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool) { /* Can't check gen, because it's not been initialized. */ + AVER(gen != NULL); AVERT(Chain, chain); AVER(nr <= chain->genCount); AVERT(Pool, pool); + AVER(PoolHasAttr(pool, AttrGC)); gen->nr = nr; gen->pool = pool; diff --git a/mps/code/trace.c b/mps/code/trace.c index 61e9d396155..5a656e9489d 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1503,21 +1503,31 @@ static Res traceCondemnAll(Trace trace) { Res res; Arena arena; - Ring chainNode, nextChainNode; + Ring poolNode, nextPoolNode, chainNode, nextChainNode; Bool haveWhiteSegs = FALSE; arena = trace->arena; AVERT(Arena, arena); - /* Condemn all the chains. */ - RING_FOR(chainNode, &arena->chainRing, nextChainNode) { - Chain chain = RING_ELT(Chain, chainRing, chainNode); - AVERT(Chain, chain); - res = ChainCondemnAll(chain, trace); - if(res != ResOK) - goto failBegin; - haveWhiteSegs = TRUE; + /* Condemn all segments in pools with the GC attribute. */ + RING_FOR(poolNode, &ArenaGlobals(arena)->poolRing, nextPoolNode) { + Pool pool = RING_ELT(Pool, arenaRing, poolNode); + AVERT(Pool, pool); + + if (PoolHasAttr(pool, AttrGC)) { + Ring segNode, nextSegNode; + RING_FOR(segNode, PoolSegRing(pool), nextSegNode) { + Seg seg = SegOfPoolRing(segNode); + AVERT(Seg, seg); + + res = TraceAddWhite(trace, seg); + if (res != ResOK) + goto failBegin; + haveWhiteSegs = TRUE; + } + } } + /* Notify all the chains. */ RING_FOR(chainNode, &arena->chainRing, nextChainNode) { Chain chain = RING_ELT(Chain, chainRing, chainNode); From 932d72770b996d30fde5a71b3412aa0f45c7171d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 21:40:59 +0100 Subject: [PATCH 3/8] Separate jobs for lo and awl finalization. Copied from Perforce Change: 185743 ServerID: perforce.ravenbrook.com --- mps/code/finaltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c index a9580bfcbdf..f449d7e1acf 100644 --- a/mps/code/finaltest.c +++ b/mps/code/finaltest.c @@ -255,7 +255,7 @@ static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain) test_pool(mode, arena, chain, mps_class_amc()); test_pool(mode, arena, chain, mps_class_amcz()); test_pool(mode, arena, chain, mps_class_ams()); - /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003772 */ + /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003773 */ /* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */ } From 5b54651076ab26c81ac154124ccd685a193c0746 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 21:57:16 +0100 Subject: [PATCH 4/8] Fix indentation. Copied from Perforce Change: 185746 ServerID: perforce.ravenbrook.com --- mps/code/locus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/locus.c b/mps/code/locus.c index e69b276ab93..6e6e22128b7 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -292,12 +292,13 @@ double ChainDeferral(Chain chain) AVERT(Chain, chain); - if (chain->activeTraces == TraceSetEMPTY) + if (chain->activeTraces == TraceSetEMPTY) { for (i = 0; i < chain->genCount; ++i) { double genTime = chain->gens[i].capacity * 1024.0 - (double)GenDescNewSize(&chain->gens[i]); if (genTime < time) time = genTime; + } } return time; From 294c4a97cd8d19093042a162642b4e6cfac16013 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 22 Apr 2014 23:18:42 +0100 Subject: [PATCH 5/8] Test the arena default chain. set the commit limit to make sure that the collector can make progress. Copied from Perforce Change: 185749 ServerID: perforce.ravenbrook.com --- mps/code/amsss.c | 90 +++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/mps/code/amsss.c b/mps/code/amsss.c index 1d04f199349..e4e66ae0529 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -27,7 +27,7 @@ #define totalSizeSTEP 200 * (size_t)1024 /* objNULL needs to be odd so that it's ignored in exactRoots. */ #define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED)) -#define testArenaSIZE ((size_t)16<<20) +#define testArenaSIZE ((size_t)1<<20) #define initTestFREQ 3000 #define splatTestFREQ 6000 static mps_gen_param_s testChain[1] = { { 160, 0.90 } }; @@ -107,7 +107,8 @@ static mps_addr_t make(void) static mps_pool_debug_option_s freecheckOptions = { NULL, 0, (const void *)"Dead", 4 }; -static void *test(void *arg, size_t haveAmbigous) +static void test_pool(mps_class_t pool_class, mps_arg_s args[], + size_t haveAmbiguous) { mps_pool_t pool; mps_root_t exactRoot, ambigRoot = NULL; @@ -116,14 +117,13 @@ static void *test(void *arg, size_t haveAmbigous) mps_ap_t busy_ap; mps_addr_t busy_init; - pool = (mps_pool_t)arg; - + die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create"); die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate"); die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2"); for(i = 0; i < exactRootsCOUNT; ++i) exactRoots[i] = objNULL; - if (haveAmbigous) + if (haveAmbiguous) for(i = 0; i < ambigRootsCOUNT; ++i) ambigRoots[i] = rnd_addr(); @@ -132,7 +132,7 @@ static void *test(void *arg, size_t haveAmbigous) &exactRoots[0], exactRootsCOUNT, (mps_word_t)1), "root_create_table(exact)"); - if (haveAmbigous) + if (haveAmbiguous) die(mps_root_create_table(&ambigRoot, arena, mps_rank_ambig(), (mps_rm_t)0, &ambigRoots[0], ambigRootsCOUNT), @@ -154,7 +154,7 @@ static void *test(void *arg, size_t haveAmbigous) } r = (size_t)rnd(); - if (!haveAmbigous || (r & 1)) { + if (!haveAmbiguous || (r & 1)) { i = (r >> 1) % exactRootsCOUNT; if (exactRoots[i] != objNULL) cdie(dylan_check(exactRoots[i]), "dying root check"); @@ -187,10 +187,10 @@ static void *test(void *arg, size_t haveAmbigous) mps_ap_destroy(busy_ap); mps_ap_destroy(ap); mps_root_destroy(exactRoot); - if (haveAmbigous) + if (haveAmbiguous) mps_root_destroy(ambigRoot); - return NULL; + mps_pool_destroy(pool); } @@ -199,68 +199,66 @@ int main(int argc, char *argv[]) mps_thr_t thread; mps_fmt_t format; mps_chain_t chain; - mps_pool_t pool; - void *r; testlib_init(argc, argv); die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), "arena_create"); + die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "commit_limit_set"); + mps_message_type_enable(arena, mps_message_type_gc_start()); mps_message_type_enable(arena, mps_message_type_gc()); die(mps_thread_reg(&thread, arena), "thread_reg"); die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create"); die(mps_chain_create(&chain, arena, 1, testChain), "chain_create"); - /* TODO: Add tests using the arena default chain. */ + printf("\n\n*** AMS with !CHAIN and SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); + test_pool(mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); - printf("\n\n****************************** Testing AMS Debug\n"); + printf("\n\n*** AMS with !CHAIN and !SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); + test_pool(mps_class_ams(), args, FALSE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS with CHAIN and SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); + test_pool(mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS with CHAIN and !SUPPORT_AMBIGUOUS\n"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); + test_pool(mps_class_ams(), args, FALSE); + } MPS_ARGS_END(args); + + printf("\n\n*** AMS Debug with CHAIN and !SUPPORT_AMBIGUOUS\n"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams_debug(), args), - "pool_create(ams_debug,share)"); + test_pool(mps_class_ams_debug(), args, FALSE); } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 0); - mps_pool_destroy(pool); - printf("\n\n****************************** Testing AMS Debug\n"); + printf("\n\n*** AMS Debug with CHAIN and SUPPORT_AMBIGUOUS\n"); MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams_debug(), args), - "pool_create(ams_debug,ambig)"); + test_pool(mps_class_ams_debug(), args, TRUE); } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 1); - mps_pool_destroy(pool); - - printf("\n\n****************************** Testing AMS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams(), args), - "pool_create(ams,ambig)"); - } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 1); - mps_pool_destroy(pool); - - printf("\n\n****************************** Testing AMS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - die(mps_pool_create_k(&pool, arena, mps_class_ams(), args), - "pool_create(ams,share)"); - } MPS_ARGS_END(args); - mps_tramp(&r, test, pool, 0); - mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); From 1821ccc3096ed10dcb814dd0d5d3e8fa542c6c4d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 23 Apr 2014 19:42:27 +0100 Subject: [PATCH 6/8] Test all 8 combinations of debug, chain, ambig. Copied from Perforce Change: 185763 ServerID: perforce.ravenbrook.com --- mps/code/amsss.c | 65 ++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/mps/code/amsss.c b/mps/code/amsss.c index e4e66ae0529..8538fd354e2 100644 --- a/mps/code/amsss.c +++ b/mps/code/amsss.c @@ -196,6 +196,7 @@ static void test_pool(mps_class_t pool_class, mps_arg_s args[], int main(int argc, char *argv[]) { + int i; mps_thr_t thread; mps_fmt_t format; mps_chain_t chain; @@ -212,53 +213,23 @@ int main(int argc, char *argv[]) die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create"); die(mps_chain_create(&chain, arena, 1, testChain), "chain_create"); - printf("\n\n*** AMS with !CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - test_pool(mps_class_ams(), args, TRUE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with !CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - test_pool(mps_class_ams(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - test_pool(mps_class_ams(), args, TRUE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS with CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - test_pool(mps_class_ams(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS Debug with CHAIN and !SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, FALSE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - test_pool(mps_class_ams_debug(), args, FALSE); - } MPS_ARGS_END(args); - - printf("\n\n*** AMS Debug with CHAIN and SUPPORT_AMBIGUOUS\n"); - MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); - MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); - MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, TRUE); - MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); - test_pool(mps_class_ams_debug(), args, TRUE); - } MPS_ARGS_END(args); + for (i = 0; i < 8; i++) { + int debug = i % 2; + int ownChain = (i / 2) % 2; + int ambig = (i / 4) % 2; + printf("\n\n*** AMS%s with %sCHAIN and %sSUPPORT_AMBIGUOUS\n", + debug ? " Debug" : "", + ownChain ? "" : "!", + ambig ? "" : "!"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + if (chain) + MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain); + MPS_ARGS_ADD(args, MPS_KEY_AMS_SUPPORT_AMBIGUOUS, ambig); + MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &freecheckOptions); + test_pool(debug ? mps_class_ams_debug() : mps_class_ams(), args, TRUE); + } MPS_ARGS_END(args); + } mps_chain_destroy(chain); mps_fmt_destroy(format); From fb56a08e49185009b92653ddb4f6d6da7a890047 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 23 Apr 2014 20:22:19 +0100 Subject: [PATCH 7/8] Tracecondemnzones could leave the white set inconsistent if traceaddwhite failed. add an assertion to cover this case (corresponding to the similar assertion in tracecondemnall). Copied from Perforce Change: 185765 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 5a656e9489d..76769583748 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -390,6 +390,7 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) Seg seg; Arena arena; Res res; + Bool haveWhiteSegs = FALSE; AVERT(Trace, trace); AVER(condemnedSet != ZoneSetEMPTY); @@ -414,8 +415,11 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) && ZoneSetSuper(condemnedSet, ZoneSetOfSeg(arena, seg))) { res = TraceAddWhite(trace, seg); - if(res != ResOK) + if(res != ResOK) { + AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ return res; + } + haveWhiteSegs = TRUE; } } while (SegNext(&seg, arena, seg)); } From 28a6bfe289067477c804506de29fd9e2f0d2e98e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 25 Apr 2014 17:41:56 +0100 Subject: [PATCH 8/8] Explain traceaddwhite failure logic as requested by nb in . Copied from Perforce Change: 185800 ServerID: perforce.ravenbrook.com --- mps/code/trace.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mps/code/trace.c b/mps/code/trace.c index 76769583748..f94d245fbf7 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -415,10 +415,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) && ZoneSetSuper(condemnedSet, ZoneSetOfSeg(arena, seg))) { res = TraceAddWhite(trace, seg); - if(res != ResOK) { - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ - return res; - } + if(res != ResOK) + goto failBegin; haveWhiteSegs = TRUE; } } while (SegNext(&seg, arena, seg)); @@ -430,6 +428,10 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) AVER(ZoneSetSuper(condemnedSet, trace->white)); return ResOK; + +failBegin: + AVER(!haveWhiteSegs); /* See .whiten.fail. */ + return res; } @@ -1541,7 +1543,14 @@ static Res traceCondemnAll(Trace trace) return ResOK; failBegin: - AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */ + /* .whiten.fail: If we successfully whitened one or more segments, + * but failed to whiten them all, then the white sets would now be + * inconsistent. This can't happen in practice (at time of writing) + * because all PoolWhiten methods always succeed. If we ever have a + * pool class that fails to whiten a segment, then this assertion + * will be triggered. In that case, we'll have to recover here by + * blackening the segments again. */ + AVER(!haveWhiteSegs); return res; }