Bug 1544885 - Don't immediately run another GC slice in idle time if there's no work to do on the main thread r=smaug r=pbone

Differential Revision: https://phabricator.services.mozilla.com/D27889
This commit is contained in:
Jon Coppeard 2019-04-17 14:04:32 +01:00
Родитель bda8d7ed6b
Коммит 3538d42c33
4 изменённых файлов: 38 добавлений и 7 удалений

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

@ -1769,12 +1769,11 @@ bool InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData) {
Telemetry::Accumulate(Telemetry::GC_SLICE_DURING_IDLE, percent);
}
// If we didn't use the whole budget, we're past the foreground sweeping slice
// and will need to wait for the background tasks to finish, or we're at the
// last slice. Return value on the latter case doesn't matter, and on the
// former we want to wait a bit before polling again.
// Returning false makes IdleTaskRunner postpone the next call a bit.
return int64_t(sliceDuration.ToMilliseconds()) >= budget;
// If the GC doesn't have any more work to do on the foreground thread (and
// e.g. is waiting for background sweeping to finish) then return false to
// make IdleTaskRunner postpone the next call a bit.
JSContext* cx = danger::GetJSContext();
return JS::IncrementalGCHasForegroundWork(cx);
}
// static

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

@ -565,6 +565,14 @@ extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx,
extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason,
int64_t millis = 0);
/**
* Return whether an incremental GC has work to do on the foreground thread and
* would make progress if a slice was run now. If this returns false then the GC
* is waiting for background threads to finish their work and a slice started
* now would return immediately.
*/
extern JS_PUBLIC_API bool IncrementalGCHasForegroundWork(JSContext* cx);
/**
* If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
* by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),

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

@ -7190,6 +7190,23 @@ void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason,
MOZ_ASSERT(marker.markColor() == MarkColor::Black);
}
bool GCRuntime::hasForegroundWork() const {
switch (incrementalState) {
case State::NotActive:
// Incremental GC is not running and no work is pending.
return false;
case State::Finalize:
// We yield in the Finalize state to wait for background sweeping.
return !isBackgroundSweeping();
case State::Decommit:
// We yield in the Decommit state to wait for background decommit.
return !decommitTask.isRunning();
default:
// In all other states there is still work to do.
return true;
}
}
gc::AbortReason gc::IsIncrementalGCUnsafe(JSRuntime* rt) {
MOZ_ASSERT(!rt->mainContextFromOwnThread()->suppressGC);
@ -8564,6 +8581,12 @@ JS_PUBLIC_API void JS::IncrementalGCSlice(JSContext* cx, GCReason reason,
cx->runtime()->gc.gcSlice(reason, millis);
}
JS_PUBLIC_API bool JS::IncrementalGCHasForegroundWork(JSContext* cx) {
MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
CHECK_THREAD(cx);
return cx->runtime()->gc.hasForegroundWork();
}
JS_PUBLIC_API void JS::FinishIncrementalGC(JSContext* cx, GCReason reason) {
cx->runtime()->gc.finishGC(reason);
}

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

@ -308,7 +308,7 @@ class GCRuntime {
State state() const { return incrementalState; }
bool isHeapCompacting() const { return state() == State::Compact; }
bool isForegroundSweeping() const { return state() == State::Sweep; }
bool isBackgroundSweeping() { return sweepTask.isRunning(); }
bool isBackgroundSweeping() const { return sweepTask.isRunning(); }
void waitBackgroundSweepEnd();
void waitBackgroundAllocEnd() { allocTask.cancelAndWait(); }
void waitBackgroundFreeEnd();
@ -332,6 +332,7 @@ class GCRuntime {
incrementalAllowed;
}
bool isIncrementalGCInProgress() const { return state() != State::NotActive; }
bool hasForegroundWork() const;
bool isCompactingGCEnabled() const;