зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1855376 - Free stacks of extra parallel markers between GCs r=sfink
We currently keep all mark stacks allocated after GC, shrunk to their default size. For parallel marking we can free the mark stacks of all markers apart from the first. If we fail to allocate them at the start of marking we can fall back to not marking in parallel. This fixes the AWSY regression. The patch also changes GCMarker::reset() to cover everything that happens in GCMarker::stop() so you don't need to call both. Differential Revision: https://phabricator.services.mozilla.com/D189342
This commit is contained in:
Родитель
226c8aba6a
Коммит
9bb856e20b
|
@ -2848,11 +2848,6 @@ void GCRuntime::beginMarkPhase(AutoGCSession& session) {
|
|||
// get here.
|
||||
incMajorGcNumber();
|
||||
|
||||
MOZ_ASSERT(!hasDelayedMarking());
|
||||
for (auto& marker : markers) {
|
||||
marker->start();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
queuePos = 0;
|
||||
queueMarkColor.reset();
|
||||
|
@ -2872,6 +2867,19 @@ void GCRuntime::beginMarkPhase(AutoGCSession& session) {
|
|||
}
|
||||
}
|
||||
|
||||
updateSchedulingStateOnGCStart();
|
||||
stats().measureInitialHeapSize();
|
||||
|
||||
useParallelMarking = SingleThreadedMarking;
|
||||
if (canMarkInParallel() && initParallelMarkers()) {
|
||||
useParallelMarking = AllowParallelMarking;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!hasDelayedMarking());
|
||||
for (auto& marker : markers) {
|
||||
marker->start();
|
||||
}
|
||||
|
||||
if (rt->isBeingDestroyed()) {
|
||||
checkNoRuntimeRoots(session);
|
||||
} else {
|
||||
|
@ -2880,9 +2888,6 @@ void GCRuntime::beginMarkPhase(AutoGCSession& session) {
|
|||
traceRuntimeForMajorGC(marker().tracer(), session);
|
||||
marker().setRootMarkingMode(false);
|
||||
}
|
||||
|
||||
updateSchedulingStateOnGCStart();
|
||||
stats().measureInitialHeapSize();
|
||||
}
|
||||
|
||||
void GCRuntime::findDeadCompartments() {
|
||||
|
@ -2965,6 +2970,8 @@ void GCRuntime::updateSchedulingStateOnGCStart() {
|
|||
}
|
||||
|
||||
inline bool GCRuntime::canMarkInParallel() const {
|
||||
MOZ_ASSERT(state() >= gc::State::MarkRoots);
|
||||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
// OOM testing limits the engine to using a single helper thread.
|
||||
if (oom::simulator.targetThread() == THREAD_TYPE_GCPARALLEL) {
|
||||
|
@ -2976,6 +2983,21 @@ inline bool GCRuntime::canMarkInParallel() const {
|
|||
tunables.parallelMarkingThresholdBytes();
|
||||
}
|
||||
|
||||
bool GCRuntime::initParallelMarkers() {
|
||||
MOZ_ASSERT(canMarkInParallel());
|
||||
|
||||
// Allocate stack for parallel markers. The first marker always has stack
|
||||
// allocated. Other markers have their stack freed in
|
||||
// GCRuntime::finishCollection.
|
||||
for (size_t i = 1; i < markers.length(); i++) {
|
||||
if (!markers[i]->initStack()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IncrementalProgress GCRuntime::markUntilBudgetExhausted(
|
||||
SliceBudget& sliceBudget, ParallelMarking allowParallelMarking,
|
||||
ShouldReportMarkTime reportTime) {
|
||||
|
@ -2987,7 +3009,8 @@ IncrementalProgress GCRuntime::markUntilBudgetExhausted(
|
|||
return NotFinished;
|
||||
}
|
||||
|
||||
if (allowParallelMarking && canMarkInParallel()) {
|
||||
if (allowParallelMarking) {
|
||||
MOZ_ASSERT(canMarkInParallel());
|
||||
MOZ_ASSERT(parallelMarkingEnabled);
|
||||
MOZ_ASSERT(reportTime);
|
||||
MOZ_ASSERT(!isBackgroundMarking());
|
||||
|
@ -3177,8 +3200,14 @@ void GCRuntime::finishCollection(JS::GCReason reason) {
|
|||
assertBackgroundSweepingFinished();
|
||||
|
||||
MOZ_ASSERT(!hasDelayedMarking());
|
||||
for (auto& marker : markers) {
|
||||
for (size_t i = 0; i < markers.length(); i++) {
|
||||
const auto& marker = markers[i];
|
||||
marker->stop();
|
||||
if (i == 0) {
|
||||
marker->resetStackCapacity();
|
||||
} else {
|
||||
marker->freeStack();
|
||||
}
|
||||
}
|
||||
|
||||
maybeStopPretenuring();
|
||||
|
@ -3623,7 +3652,7 @@ void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason,
|
|||
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK);
|
||||
if (markUntilBudgetExhausted(budget, AllowParallelMarking) ==
|
||||
if (markUntilBudgetExhausted(budget, useParallelMarking) ==
|
||||
NotFinished) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -375,6 +375,10 @@ class GCMarker {
|
|||
|
||||
static void moveWork(GCMarker* dst, GCMarker* src);
|
||||
|
||||
[[nodiscard]] bool initStack();
|
||||
void resetStackCapacity();
|
||||
void freeStack();
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
static GCMarker* fromTracer(JSTracer* trc) {
|
||||
|
|
|
@ -776,6 +776,8 @@ class GCRuntime {
|
|||
ParallelMarking allowParallelMarking = SingleThreadedMarking,
|
||||
ShouldReportMarkTime reportTime = ReportMarkTime);
|
||||
bool canMarkInParallel() const;
|
||||
bool initParallelMarkers();
|
||||
void finishParallelMarkers();
|
||||
|
||||
bool hasMarkingWork(MarkColor color) const;
|
||||
|
||||
|
@ -1099,6 +1101,9 @@ class GCRuntime {
|
|||
/* Whether the heap will be compacted at the end of GC. */
|
||||
MainThreadData<bool> isCompacting;
|
||||
|
||||
/* Whether to use parallel marking. */
|
||||
MainThreadData<ParallelMarking> useParallelMarking;
|
||||
|
||||
/* The invocation kind of the current GC, set at the start of collection. */
|
||||
MainThreadOrGCTaskData<mozilla::Maybe<JS::GCOptions>> maybeGcOptions;
|
||||
|
||||
|
|
|
@ -1269,6 +1269,24 @@ void GCMarker::moveWork(GCMarker* dst, GCMarker* src) {
|
|||
MarkStack::moveWork(dst->stack, src->stack);
|
||||
}
|
||||
|
||||
bool GCMarker::initStack() {
|
||||
MOZ_ASSERT(!isActive());
|
||||
MOZ_ASSERT(markColor_ == gc::MarkColor::Black);
|
||||
return stack.init();
|
||||
}
|
||||
|
||||
void GCMarker::resetStackCapacity() {
|
||||
MOZ_ASSERT(!isActive());
|
||||
MOZ_ASSERT(markColor_ == gc::MarkColor::Black);
|
||||
(void)stack.resetStackCapacity();
|
||||
}
|
||||
|
||||
void GCMarker::freeStack() {
|
||||
MOZ_ASSERT(!isActive());
|
||||
MOZ_ASSERT(markColor_ == gc::MarkColor::Black);
|
||||
stack.clearAndFreeStack();
|
||||
}
|
||||
|
||||
bool GCMarker::markUntilBudgetExhausted(SliceBudget& budget,
|
||||
ShouldReportMarkTime reportTime) {
|
||||
#ifdef DEBUG
|
||||
|
@ -2002,13 +2020,14 @@ void GCMarker::stop() {
|
|||
}
|
||||
state = NotActive;
|
||||
|
||||
(void)stack.resetStackCapacity();
|
||||
otherStack.clearAndFreeStack();
|
||||
ClearEphemeronEdges(runtime());
|
||||
unmarkGrayStack.clearAndFree();
|
||||
}
|
||||
|
||||
void GCMarker::reset() {
|
||||
state = NotActive;
|
||||
|
||||
stack.clearAndResetCapacity();
|
||||
otherStack.clearAndFreeStack();
|
||||
ClearEphemeronEdges(runtime());
|
||||
|
|
|
@ -1131,7 +1131,7 @@ IncrementalProgress GCRuntime::markGray(JS::GCContext* gcx,
|
|||
SliceBudget& budget) {
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK);
|
||||
|
||||
if (markUntilBudgetExhausted(budget, AllowParallelMarking) == NotFinished) {
|
||||
if (markUntilBudgetExhausted(budget, useParallelMarking) == NotFinished) {
|
||||
return NotFinished;
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1720,7 @@ IncrementalProgress GCRuntime::markDuringSweeping(JS::GCContext* gcx,
|
|||
}
|
||||
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK);
|
||||
return markUntilBudgetExhausted(budget, AllowParallelMarking);
|
||||
return markUntilBudgetExhausted(budget, useParallelMarking);
|
||||
}
|
||||
|
||||
void GCRuntime::beginSweepPhase(JS::GCReason reason, AutoGCSession& session) {
|
||||
|
|
|
@ -393,7 +393,6 @@ void gc::GCRuntime::endVerifyPreBarriers() {
|
|||
}
|
||||
|
||||
marker().reset();
|
||||
marker().stop();
|
||||
resetDelayedMarking();
|
||||
|
||||
js_delete(trc);
|
||||
|
@ -586,7 +585,6 @@ void js::gc::MarkingValidator::nonIncrementalMark(AutoGCSession& session) {
|
|||
}
|
||||
|
||||
MOZ_ASSERT(gcmarker->isDrained());
|
||||
gcmarker->reset();
|
||||
|
||||
ClearMarkBits<GCZonesIter>(gc);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче