зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1119759 - Add gcstart() test function to start an incremental GC r=terrence
This commit is contained in:
Родитель
b1c5f6e284
Коммит
774d8b3183
|
@ -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;
|
||||
}
|
||||
|
@ -2190,7 +2239,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,
|
||||
|
@ -2305,9 +2354,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,40 @@
|
|||
// Exercise incremental compacting GC
|
||||
// Run with MOZ_GCTIMER to see the timings
|
||||
|
||||
if (!("gcstate" in this && "gczeal" in this))
|
||||
quit();
|
||||
|
||||
gczeal(0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче