Bug 763984: Add new zeal modes to test incremental GC r=billm

--HG--
extra : rebase_source : 0392bc3985442eb3b378b1f5a47a757f55106fdc
This commit is contained in:
Jon Coppeard 2012-06-22 11:25:21 +01:00
parent cbf817fec3
commit 07970c9678
4 changed files with 75 additions and 11 deletions

View File

@ -746,6 +746,7 @@ JSRuntime::JSRuntime()
gcZealFrequency(0),
gcNextScheduled(0),
gcDeterministicOnly(false),
gcIncrementalLimit(0),
#endif
gcCallback(NULL),
gcSliceCallback(NULL),
@ -6671,7 +6672,10 @@ JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
" 4: Verify write barriers between instructions\n"
" 5: Verify write barriers between paints\n"
" 6: Verify stack rooting (ignoring XML and Reflect)\n"
" 7: Verify stack rooting (all roots)\n");
" 7: Verify stack rooting (all roots)\n"
" 8: Incremental GC in two slices: 1) mark roots 2) finish collection\n"
" 9: Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
" 10: Incremental GC in multiple slices\n");
}
const char *p = strchr(env, ',');
zeal = atoi(env);

View File

@ -586,8 +586,9 @@ struct JSRuntime : js::RuntimeFriendFields
* gcNextScheduled is decremented. When it reaches zero, we do either a
* full or a compartmental GC, based on gcDebugCompartmentGC.
*
* At this point, if gcZeal_ == 2 then gcNextScheduled is reset to the
* value of gcZealFrequency. Otherwise, no additional GCs take place.
* At this point, if gcZeal_ is one of the types that trigger periodic
* collection, then gcNextScheduled is reset to the value of
* gcZealFrequency. Otherwise, no additional GCs take place.
*
* You can control these values in several ways:
* - Pass the -Z flag to the shell (see the usage info for details)
@ -599,12 +600,16 @@ struct JSRuntime : js::RuntimeFriendFields
*
* We use gcZeal_ == 4 to enable write barrier verification. See the comment
* in jsgc.cpp for more information about this.
*
* gcZeal_ values from 8 to 10 periodically run different types of
* incremental GC.
*/
#ifdef JS_GC_ZEAL
int gcZeal_;
int gcZealFrequency;
int gcNextScheduled;
bool gcDeterministicOnly;
int gcIncrementalLimit;
js::Vector<JSObject *, 0, js::SystemAllocPolicy> gcSelectedForMarking;
@ -612,8 +617,12 @@ struct JSRuntime : js::RuntimeFriendFields
bool needZealousGC() {
if (gcNextScheduled > 0 && --gcNextScheduled == 0) {
if (gcZeal() == js::gc::ZealAllocValue)
if (gcZeal() == js::gc::ZealAllocValue ||
(gcZeal() >= js::gc::ZealIncrementalRootsThenFinish &&
gcZeal() <= js::gc::ZealIncrementalMultipleSlices))
{
gcNextScheduled = gcZealFrequency;
}
return true;
}
return false;

View File

@ -3590,12 +3590,23 @@ class AutoCopyFreeListToArenas {
};
static void
IncrementalMarkSlice(JSRuntime *rt, int64_t budget, JSGCInvocationKind gckind, bool *shouldSweep)
IncrementalMarkSlice(JSRuntime *rt, int64_t budget, gcreason::Reason reason, bool *shouldSweep)
{
AutoGCSlice slice(rt);
gc::State initialState = rt->gcIncrementalState;
*shouldSweep = false;
int zeal = 0;
#ifdef JS_GC_ZEAL
if (reason == gcreason::DEBUG_GC) {
// Do the collection type specified by zeal mode only if the collection
// was triggered by RunDebugGC().
zeal = rt->gcZeal();
}
#endif
if (rt->gcIncrementalState == NO_INCREMENTAL) {
rt->gcIncrementalState = MARK_ROOTS;
rt->gcLastMarkSlice = false;
@ -3604,9 +3615,11 @@ IncrementalMarkSlice(JSRuntime *rt, int64_t budget, JSGCInvocationKind gckind, b
if (rt->gcIncrementalState == MARK_ROOTS) {
BeginMarkPhase(rt);
rt->gcIncrementalState = MARK;
if (zeal == ZealIncrementalRootsThenFinish)
return;
}
*shouldSweep = false;
if (rt->gcIncrementalState == MARK) {
SliceBudget sliceBudget(budget);
@ -3614,6 +3627,12 @@ IncrementalMarkSlice(JSRuntime *rt, int64_t budget, JSGCInvocationKind gckind, b
if (!rt->gcMarker.hasBufferedGrayRoots())
sliceBudget.reset();
if (zeal == ZealIncrementalRootsThenFinish ||
zeal == ZealIncrementalMarkAllThenFinish)
{
sliceBudget.reset();
}
#ifdef JS_GC_ZEAL
if (!rt->gcSelectedForMarking.empty()) {
for (JSObject **obj = rt->gcSelectedForMarking.begin();
@ -3631,7 +3650,12 @@ IncrementalMarkSlice(JSRuntime *rt, int64_t budget, JSGCInvocationKind gckind, b
}
if (finished) {
JS_ASSERT(rt->gcMarker.isDrained());
if (initialState == MARK && !rt->gcLastMarkSlice && budget != SliceBudget::Unlimited) {
if (!rt->gcLastMarkSlice &&
((initialState == MARK && budget != SliceBudget::Unlimited) ||
zeal == ZealIncrementalMarkAllThenFinish) &&
zeal != ZealIncrementalRootsThenFinish)
{
rt->gcLastMarkSlice = true;
} else {
EndMarkPhase(rt);
@ -3732,7 +3756,7 @@ BudgetIncrementalGC(JSRuntime *rt, int64_t *budget)
* the marking implementation.
*/
static JS_NEVER_INLINE void
GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind)
GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind, gcreason::Reason reason)
{
#ifdef DEBUG
for (CompartmentsIter c(rt); !c.done(); c.next())
@ -3780,7 +3804,7 @@ GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gcki
NonIncrementalMark(rt, gckind);
shouldSweep = true;
} else {
IncrementalMarkSlice(rt, budget, gckind, &shouldSweep);
IncrementalMarkSlice(rt, budget, reason, &shouldSweep);
}
#ifdef DEBUG
@ -3891,7 +3915,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
}
rt->gcPoke = false;
GCCycle(rt, incremental, budget, gckind);
GCCycle(rt, incremental, budget, gckind, reason);
if (rt->gcIncrementalState == NO_INCREMENTAL) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_GC_END);
@ -4123,8 +4147,32 @@ void
RunDebugGC(JSContext *cx)
{
#ifdef JS_GC_ZEAL
JSRuntime *rt = cx->runtime;
PrepareForDebugGC(cx->runtime);
RunLastDitchGC(cx, gcreason::DEBUG_GC);
int type = rt->gcZeal();
if (type == ZealIncrementalRootsThenFinish ||
type == ZealIncrementalMarkAllThenFinish ||
type == ZealIncrementalMultipleSlices)
{
int64_t budget;
if (type == ZealIncrementalMultipleSlices) {
// Start with a small slice limit and double it every slice. This ensure that we get
// multiple slices, and collection runs to completion.
if (rt->gcIncrementalState == NO_INCREMENTAL)
rt->gcIncrementalLimit = rt->gcZealFrequency / 2;
else
rt->gcIncrementalLimit *= 2;
budget = SliceBudget::WorkBudget(rt->gcIncrementalLimit);
} else {
// This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
budget = SliceBudget::WorkBudget(1);
}
Collect(rt, true, budget, GC_NORMAL, gcreason::DEBUG_GC);
} else {
Collect(rt, false, SliceBudget::Unlimited, GC_NORMAL, gcreason::DEBUG_GC);
}
#endif
}

View File

@ -1069,6 +1069,9 @@ const int ZealVerifierValue = 4;
const int ZealFrameVerifierValue = 5;
const int ZealStackRootingSafeValue = 6;
const int ZealStackRootingValue = 7;
const int ZealIncrementalRootsThenFinish = 8;
const int ZealIncrementalMarkAllThenFinish = 9;
const int ZealIncrementalMultipleSlices = 10;
#ifdef JS_GC_ZEAL