Bug 1118996 - Add gcstart() test function to start an incremental GC r=terrence

:
This commit is contained in:
Jon Coppeard 2015-01-12 10:29:38 +00:00
Родитель 1bb19d6931
Коммит 0dda38a8a3
6 изменённых файлов: 116 добавлений и 18 удалений

Просмотреть файл

@ -570,6 +570,8 @@ GCState(JSContext *cx, unsigned argc, jsval *vp)
state = "mark";
else if (globalState == gc::SWEEP)
state = "sweep";
else if (globalState == gc::COMPACT)
state = "compact";
else
MOZ_CRASH("Unobserveable global GC state");
@ -597,6 +599,48 @@ DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
}
#endif /* JS_GC_ZEAL */
static bool
StartGC(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() > 2) {
RootedObject callee(cx, &args.callee());
ReportUsageError(cx, callee, "Wrong number of arguments");
return false;
}
SliceBudget budget;
if (args.length() >= 1) {
uint32_t work = 0;
if (!ToUint32(cx, args[0], &work))
return false;
budget = SliceBudget(WorkBudget(work));
}
bool shrinking = false;
if (args.length() >= 2) {
Value arg = args[1];
if (arg.isString()) {
if (!JS_StringEqualsAscii(cx, arg.toString(), "shrinking", &shrinking))
return false;
}
}
JSRuntime *rt = cx->runtime();
if (rt->gc.isIncrementalGCInProgress()) {
RootedObject callee(cx, &args.callee());
ReportUsageError(cx, callee, "Incremental GC already in progress");
return false;
}
JSGCInvocationKind gckind = shrinking ? GC_SHRINK : GC_NORMAL;
rt->gc.startDebugGC(gckind, budget);
args.rval().setUndefined();
return true;
}
static bool
GCSlice(JSContext *cx, unsigned argc, Value *vp)
{
@ -616,7 +660,12 @@ GCSlice(JSContext *cx, unsigned argc, Value *vp)
budget = SliceBudget(WorkBudget(work));
}
cx->runtime()->gc.gcDebugSlice(budget);
JSRuntime *rt = cx->runtime();
if (!rt->gc.isIncrementalGCInProgress())
rt->gc.startDebugGC(GC_NORMAL, budget);
else
rt->gc.debugGCSlice(budget);
args.rval().setUndefined();
return true;
}
@ -2222,7 +2271,7 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" Run the garbage collector. When obj is given, GC only its compartment.\n"
" If 'compartment' is given, GC any compartments that were scheduled for\n"
" GC via schedulegc.\n"
" If 'shrinking' is passes as the optional second argument, perform a\n"
" If 'shrinking' is passed as the optional second argument, perform a\n"
" shrinking GC rather than a normal GC."),
JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
@ -2339,9 +2388,15 @@ gc::ZealModeHelpText),
" If true, only allow determinstic GCs to run."),
#endif
JS_FN_HELP("startgc", StartGC, 1, 0,
"startgc([n [, 'shrinking']])",
" Start an incremental GC and run a slice that processes about n objects.\n"
" If 'shrinking' is passesd as the optional second argument, perform a\n"
" shrinking GC rather than a normal GC."),
JS_FN_HELP("gcslice", GCSlice, 1, 0,
"gcslice(n)",
" Run an incremental GC slice that marks about n objects."),
"gcslice([n])",
" Start or continue an an incremental GC, running a slice that processes about n objects."),
JS_FN_HELP("validategc", ValidateGC, 1, 0,
"validategc(true|false)",

Просмотреть файл

@ -320,7 +320,8 @@ class GCRuntime
void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
void finishGC(JS::gcreason::Reason reason);
void gcDebugSlice(SliceBudget &budget);
void startDebugGC(JSGCInvocationKind gckind, SliceBudget &budget);
void debugGCSlice(SliceBudget &budget);
void runDebugGC();
inline void poke();

Просмотреть файл

@ -0,0 +1,35 @@
// Exercise incremental compacting GC
// Run with MOZ_GCTIMER to see the timings
function testCompacting(zoneCount, objectCount, sliceCount)
{
// Allocate objectCount objects in zoneCount zones
// On linux64 debug builds we will move them all
// Run compacting GC with multiple slices
var zones = [];
for (var i = 0; i < zoneCount; i++) {
var zone = newGlobal();
evaluate("var objects; " +
"function makeObjectGraph(objectCount) { " +
" objects = []; " +
" for (var i = 0; i < objectCount; i++) " +
" objects.push({ serial: i }); " +
"}",
{ global: zone });
zone.makeObjectGraph(objectCount);
zones.push(zone);
}
startgc(sliceCount, "shrinking");
while (gcstate() !== "none") {
gcslice(sliceCount);
}
return zones;
}
testCompacting(1, 100000, 100000);
testCompacting(2, 100000, 100000);
testCompacting(4, 50000, 100000);
testCompacting(2, 100000, 50000);

Просмотреть файл

@ -88,13 +88,13 @@ BEGIN_TEST(testGCFinalizeCallback)
JS_SetGCZeal(cx, 9, 1000000);
JS::PrepareForFullGC(rt);
js::SliceBudget budget(js::WorkBudget(1));
rt->gc.gcDebugSlice(budget);
rt->gc.startDebugGC(GC_NORMAL, budget);
CHECK(rt->gc.state() == js::gc::MARK);
CHECK(rt->gc.isFullGc());
JS::RootedObject global4(cx, createTestGlobal());
budget = js::SliceBudget(js::WorkBudget(1));
rt->gc.gcDebugSlice(budget);
rt->gc.debugGCSlice(budget);
CHECK(!rt->gc.isIncrementalGCInProgress());
CHECK(!rt->gc.isFullGc());
CHECK(checkMultipleGroups());

Просмотреть файл

@ -91,7 +91,8 @@ BEGIN_TEST(testWeakMap_keyDelegates)
*/
CHECK(newCCW(map, delegate));
js::SliceBudget budget(js::WorkBudget(1000000));
rt->gc.gcDebugSlice(budget);
rt->gc.startDebugGC(GC_NORMAL, budget);
CHECK(!JS::IsIncrementalGCInProgress(rt));
#ifdef DEBUG
CHECK(map->zone()->lastZoneGroupIndex() < delegate->zone()->lastZoneGroupIndex());
#endif
@ -105,7 +106,8 @@ BEGIN_TEST(testWeakMap_keyDelegates)
key = nullptr;
CHECK(newCCW(map, delegate));
budget = js::SliceBudget(js::WorkBudget(100000));
rt->gc.gcDebugSlice(budget);
rt->gc.startDebugGC(GC_NORMAL, budget);
CHECK(!JS::IsIncrementalGCInProgress(rt));
CHECK(checkSize(map, 1));
/*

Просмотреть файл

@ -6402,16 +6402,21 @@ ZonesSelected(JSRuntime *rt)
}
void
GCRuntime::gcDebugSlice(SliceBudget &budget)
GCRuntime::startDebugGC(JSGCInvocationKind gckind, SliceBudget &budget)
{
if (!ZonesSelected(rt)) {
if (isIncrementalGCInProgress())
JS::PrepareForIncrementalGC(rt);
else
JS::PrepareForFullGC(rt);
}
if (!isIncrementalGCInProgress())
invocationKind = GC_NORMAL;
MOZ_ASSERT(!isIncrementalGCInProgress());
if (!ZonesSelected(rt))
JS::PrepareForFullGC(rt);
invocationKind = gckind;
collect(true, budget, JS::gcreason::DEBUG_GC);
}
void
GCRuntime::debugGCSlice(SliceBudget &budget)
{
MOZ_ASSERT(isIncrementalGCInProgress());
if (!ZonesSelected(rt))
JS::PrepareForIncrementalGC(rt);
collect(true, budget, JS::gcreason::DEBUG_GC);
}