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:
Jon Coppeard 2023-09-28 06:48:34 +00:00
Родитель 226c8aba6a
Коммит 9bb856e20b
6 изменённых файлов: 71 добавлений и 16 удалений

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

@ -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);
}