From accddda53b1ca37995f41e4cc8566705b121a9ca Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Wed, 16 Mar 2016 23:54:41 +0000 Subject: [PATCH] Condemn only visits segments in condemned zones. Copied from Perforce Change: 190127 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- mps/code/mpm.h | 2 ++ mps/code/mpmst.h | 1 + mps/code/seg.c | 42 ++++++++++++++++++++++++++++++++++++++++++ mps/code/trace.c | 9 ++++++++- 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index f77d9e46774..09ce34e9e7f 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -240,7 +240,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) SplayTreeInit(ArenaSegSplay(arena), SegCompare, SegKey, - SplayTrivUpdate); + SegUpdate); LocusInit(arena); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index f2532be20cb..7a7a9a3f766 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -678,6 +678,7 @@ extern Bool SegOfAddr(Seg *segReturn, Arena arena, Addr addr); typedef Bool (*SegVisitor)(Seg seg, void *closure); extern Bool SegTraverse(Arena arena, SegVisitor visit, void *closure); extern void SegTraverseAndDelete(Arena arena, SegVisitor visit, void *closure); +extern Bool SegTraverseInZones(Arena arena, ZoneSet zs, SegVisitor visit, void *closure); extern Bool SegFirst(Seg *segReturn, Arena arena); extern Bool SegNext(Seg *segReturn, Arena arena, Seg seg); extern Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next); @@ -699,6 +700,7 @@ extern SegClass GCSegClassGet(void); extern void SegClassMixInNoSplitMerge(SegClass class); extern Compare SegCompare(Tree tree, TreeKey key); extern TreeKey SegKey(Tree tree); +extern void SegUpdate(SplayTree splay, Tree tree); /* DEFINE_SEG_CLASS -- define a segment class */ diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 329fea66553..aa629ee5bba 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -241,6 +241,7 @@ typedef struct SegStruct { /* segment structure */ Pool pool; /* pool that owns this segment */ RingStruct poolRing; /* link in list of segs in pool */ TreeStruct treeStruct; /* tree of all segments by address */ + ZoneSet treeZones; /* union of all zones in sub-tree */ unsigned depth : ShieldDepthWIDTH; /* see */ AccessSet pm : AccessLIMIT; /* protection mode, */ AccessSet sm : AccessLIMIT; /* shield mode, */ diff --git a/mps/code/seg.c b/mps/code/seg.c index 4daf1ca7a67..340cebe4e87 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -162,6 +162,7 @@ static Res SegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args) seg->depth = 0; RingInit(SegPoolRing(seg)); TreeInit(SegTree(seg)); + seg->treeZones = ZoneSetEMPTY; /* set by SegUpdate */ seg->sig = SegSig; /* set sig now so tract checks will see it */ /* Class specific initialization comes last */ @@ -253,6 +254,25 @@ TreeKey SegKey(Tree tree) return (TreeKey)SegBase(segOfTree(tree)); /* FIXME: See cbsBlockKey in cbs.c */ } +void SegUpdate(SplayTree splay, Tree tree) +{ + Seg seg = segOfTree(tree); + ZoneSet zones; + + UNUSED(splay); + AVERT_CRITICAL(Seg, seg); + + /* FIXME: Duplicate code with cbsUpdateZonedNode. */ + zones = ZoneSetOfRange(PoolArena(SegPool(seg)), + SegBase(seg), SegLimit(seg)); + if (TreeHasLeft(tree)) + zones = ZoneSetUnion(zones, segOfTree(TreeLeft(tree))->treeZones); + if (TreeHasRight(tree)) + zones = ZoneSetUnion(zones, segOfTree(TreeRight(tree))->treeZones); + + seg->treeZones = zones; +} + /* SegSetGrey -- change the greyness of a segment * @@ -466,6 +486,7 @@ Bool SegOfAddr(Seg *segReturn, Arena arena, Addr addr) typedef struct SegTraverseClosureStruct { SegVisitor visit; + ZoneSet zs; void *closure; } SegTraverseClosureStruct, *SegTraverseClosure; @@ -475,17 +496,38 @@ static Bool segTraverseVisit(Tree tree, void *closure) return stv->visit(segOfTree(tree), stv->closure); } +static Bool segTraverseFilter(Tree tree, void *closure) +{ + SegTraverseClosure stv = closure; + return ZoneSetInter(segOfTree(tree)->treeZones, stv->zs) != ZoneSetEMPTY; +} + Bool SegTraverse(Arena arena, SegVisitor visit, void *closure) { SegTraverseClosureStruct stvStruct; stvStruct.visit = visit; stvStruct.closure = closure; + stvStruct.zs = ZoneSetUNIV; /* not used */ return TreeTraverse(SplayTreeRoot(ArenaSegSplay(arena)), SegCompare, SegKey, segTraverseVisit, &stvStruct); } +Bool SegTraverseInZones(Arena arena, ZoneSet zs, SegVisitor visit, void *closure) +{ + SegTraverseClosureStruct stvStruct; + stvStruct.visit = visit; + stvStruct.closure = closure; + stvStruct.zs = zs; + return TreeTraversePartial(SplayTreeRoot(ArenaSegSplay(arena)), + SegCompare, SegKey, + segTraverseFilter, + TreeNoRange, + segTraverseVisit, + &stvStruct); +} + void SegTraverseAndDelete(Arena arena, SegVisitor visit, void *closure) { SegTraverseClosureStruct stvStruct; diff --git a/mps/code/trace.c b/mps/code/trace.c index 6f4ded93ed2..09ed44e788d 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -484,7 +484,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet) tczStruct.condemnedSet = condemnedSet; tczStruct.haveWhiteSegs = FALSE; tczStruct.res = ResOK; - if (!SegTraverse(trace->arena, traceCondemnZonesVisit, &tczStruct)) { + if (!SegTraverseInZones(trace->arena, condemnedSet, + traceCondemnZonesVisit, &tczStruct)) { AVER(tczStruct.res != ResOK); AVER(TraceIsEmpty(trace)); /* See .whiten.fail. */ return tczStruct.res; @@ -975,6 +976,12 @@ static void traceReclaim(Trace trace) /* TODO: This isn't very nice, as it rebalances the segment splay tree and destroys any optimisation discovered by splaying. */ + /* TODO: This isn't very nice, as it visits every segment, + regardless of colour or zone. */ + /* TODO: Consider sort | uniq the white table? */ + /* TODO: For multiple traces, the white table is shared, and so we + must delete the pages of reclaimed segments from it. That means + visiting the table might work. */ SegTraverseAndDelete(arena, traceReclaimVisit, trace); trace->state = TraceFINISHED;