diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index b510c9779e1..0afcab6fe96 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -117,7 +117,7 @@ CFLAGSEXTERNAL = # %%VARIETY: When adding a new variety, define a macro containing the set # of flags for the new variety. CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) -CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) +CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) CFDIAG = /DCONFIG_VAR_DIAG $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) @@ -134,7 +134,7 @@ LINKFLAGSINTERNAL = /DEBUG LINKFLAGSEXTERNAL = /RELEASE LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) -LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) +LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) LFDIAG = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) diff --git a/mps/code/config.h b/mps/code/config.h index 8df33201f5f..5eb8ee50e13 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -393,6 +393,14 @@ #define AMCLargeSegPAGES ((Count)8) +/* Pool Class AWL configuration -- see poolawl.c for usage */ + +#define AWL_HAVE_SEG_SA_LIMIT TRUE +#define AWL_SEG_SA_LIMIT 200 /* TODO: Improve guesswork with measurements */ +#define AWL_HAVE_TOTAL_SA_LIMIT FALSE +#define AWL_TOTAL_SA_LIMIT 0 + + #endif /* config_h */ diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index 56d0271975b..9f5ea780787 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -68,7 +68,7 @@ */ #define EventNameMAX ((size_t)19) -#define EventCodeMAX ((EventCode)0x0071) +#define EventCodeMAX ((EventCode)0x0073) #define EVENT_LIST(EVENT, X) \ /* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \ @@ -177,7 +177,9 @@ EVENT(X, MessagesExist , 0x006E, TRUE, Arena) \ EVENT(X, ChainCondemnAuto , 0x006F, TRUE, Trace) \ EVENT(X, TraceFindGrey , 0x0070, TRUE, Trace) \ - EVENT(X, TraceBandAdvance , 0x0071, TRUE, Trace) + EVENT(X, TraceBandAdvance , 0x0071, TRUE, Trace) \ + EVENT(X, AWLDeclineTotal , 0x0072, TRUE, Trace) \ + EVENT(X, AWLDeclineSeg , 0x0073, TRUE, Trace) /* Remember to update EventNameMAX and EventCodeMAX in eventcom.h! @@ -610,6 +612,14 @@ PARAM(X, 1, W, ti) \ PARAM(X, 2, W, rank) +#define EVENT_AWLDeclineTotal_PARAMS(PARAM, X) \ + PARAM(X, 0, P, seg) /* segment declined single access */ \ + PARAM(X, 1, U, succAccesses) /* total successive accesses */ + +#define EVENT_AWLDeclineSeg_PARAMS(PARAM, X) \ + PARAM(X, 0, P, seg) /* segment declined single access */ \ + PARAM(X, 1, U, singleAccesses) /* single accesses this cycle */ + #endif /* eventdef_h */ diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index da63a4374d3..e775517a7b2 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -289,50 +289,79 @@ DEFINE_SEG_CLASS(AWLSegClass, class) } -/* Single access permission control parameters */ +/* Single access pattern control parameters + * + * These control the number of expensive emulated single-accesses we allow + * before we give up and scan a segment at whatever rank, possibly causing + * retention of weak objects. + * + * AWLSegSALimit is the number of accesses for a single segment in a GC cycle. + * AWLTotalSALimit is the total number of accesses during a GC cycle. + * + * These should be set in config.h, but are here in static variables so that + * it's possible to tweak them in a debugger. + */ -Count AWLSegSALimit = 0; /* Number of single accesses permitted per segment */ -Bool AWLHaveSegSALimit = FALSE; /* When TRUE, AWLSegSALimit applies */ +Count AWLSegSALimit = AWL_SEG_SA_LIMIT; +Bool AWLHaveSegSALimit = AWL_HAVE_SEG_SA_LIMIT; -Count AWLTotalSALimit = 0; /* Number of single accesses permitted in a row */ -Bool AWLHaveTotalSALimit = FALSE; /* When TRUE, AWLTotalSALimit applies */ +Count AWLTotalSALimit = AWL_TOTAL_SA_LIMIT; +Bool AWLHaveTotalSALimit = AWL_HAVE_TOTAL_SA_LIMIT; /* Determine whether to permit scanning a single ref. */ -static Bool AWLCanTrySingleAccess(AWL awl, Seg seg, Addr addr) +static Bool AWLCanTrySingleAccess(Arena arena, AWL awl, Seg seg, Addr addr) { + AWLSeg awlseg; + AVERT(AWL, awl); AVERT(Seg, seg); AVER(addr != NULL); /* .assume.noweak */ /* .assume.alltraceable */ - if(RankSetIsMember(SegRankSet(seg), RankWEAK)) { - AWLSeg awlseg; + if (!RankSetIsMember(SegRankSet(seg), RankWEAK)) + return FALSE; - awlseg = Seg2AWLSeg(seg); - AVERT(AWLSeg, awlseg); - - if(AWLHaveTotalSALimit) { - if(AWLTotalSALimit < awl->succAccesses) { - STATISTIC(awl->stats.declined++); - return FALSE; /* decline single access because of total limit */ - } - } - - if(AWLHaveSegSALimit) { - if(AWLSegSALimit < awlseg->singleAccesses) { - STATISTIC(awl->stats.declined++); - return FALSE; /* decline single access because of segment limit */ - } - } - - return TRUE; - - } else { - return FALSE; /* Single access only for weak segs (.assume.noweak) */ + /* If there are no traces in progress then the segment isn't read + protected and this is just an ordinary write barrier hit. No need to + scan at all. */ + if (arena->flippedTraces == TraceSetEMPTY) { + AVER(!(SegSM(seg) & AccessREAD)); + return FALSE; } + + /* The trace is already in the weak band, so we can scan the whole + segment without retention anyway. Go for it. */ + if (TraceRankForAccess(arena, seg) == RankWEAK) + return FALSE; + + awlseg = Seg2AWLSeg(seg); + AVERT(AWLSeg, awlseg); + + /* If there have been too many single accesses in a row then don't + keep trying them, even if it means retaining objects. */ + if(AWLHaveTotalSALimit) { + if(awl->succAccesses >= AWLTotalSALimit) { + STATISTIC(awl->stats.declined++); + EVENT2(AWLDeclineTotal, seg, awl->succAccesses); + return FALSE; /* decline single access because of total limit */ + } + } + + /* If there have been too many single accesses to this segment + then don't keep trying them, even if it means retaining objects. + (Observed behaviour in Open Dylan 2012-09-10 by RB.) */ + if(AWLHaveSegSALimit) { + if(awlseg->singleAccesses >= AWLSegSALimit) { + STATISTIC(awl->stats.declined++); + EVENT2(AWLDeclineSeg, seg, awlseg->singleAccesses); + return FALSE; /* decline single access because of segment limit */ + } + } + + return TRUE; } @@ -1116,9 +1145,9 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - + /* Attempt scanning a single reference if permitted */ - if(AWLCanTrySingleAccess(awl, seg, addr)) { + if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { res = PoolSingleAccess(pool, seg, addr, mode, context); switch(res) { case ResOK: