mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 17:55:50 +00:00
Bug 1398140 - Remove Ion helper thread pausing mechanism. r=luke
This commit is contained in:
parent
89f1957239
commit
85296b8b20
@ -118,21 +118,12 @@ class MIRGenerator
|
||||
|
||||
// Whether the active thread is trying to cancel this build.
|
||||
bool shouldCancel(const char* why) {
|
||||
maybePause();
|
||||
return cancelBuild_;
|
||||
}
|
||||
void cancel() {
|
||||
cancelBuild_ = true;
|
||||
}
|
||||
|
||||
void maybePause() {
|
||||
if (pauseBuild_ && *pauseBuild_)
|
||||
PauseCurrentHelperThread();
|
||||
}
|
||||
void setPauseFlag(mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild) {
|
||||
pauseBuild_ = pauseBuild;
|
||||
}
|
||||
|
||||
bool compilingWasm() const {
|
||||
return info_->compilingWasm();
|
||||
}
|
||||
@ -191,7 +182,6 @@ class MIRGenerator
|
||||
MIRGraph* graph_;
|
||||
AbortReasonOr<Ok> offThreadStatus_;
|
||||
ObjectGroupVector abortedPreliminaryGroups_;
|
||||
mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild_;
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> cancelBuild_;
|
||||
|
||||
uint32_t wasmMaxStackArgBytes_;
|
||||
|
@ -28,7 +28,6 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
|
||||
graph_(graph),
|
||||
offThreadStatus_(Ok()),
|
||||
abortedPreliminaryGroups_(*alloc_),
|
||||
pauseBuild_(nullptr),
|
||||
cancelBuild_(false),
|
||||
wasmMaxStackArgBytes_(0),
|
||||
needsOverrecursedCheck_(false),
|
||||
|
@ -283,21 +283,14 @@ CancelOffThreadIonCompileLocked(const CompilationSelector& selector, bool discar
|
||||
bool cancelled;
|
||||
do {
|
||||
cancelled = false;
|
||||
bool unpaused = false;
|
||||
for (auto& helper : *HelperThreadState().threads) {
|
||||
if (helper.ionBuilder() &&
|
||||
IonBuilderMatches(selector, helper.ionBuilder()))
|
||||
{
|
||||
helper.ionBuilder()->cancel();
|
||||
if (helper.pause) {
|
||||
helper.pause = false;
|
||||
unpaused = true;
|
||||
}
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
if (unpaused)
|
||||
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, lock);
|
||||
if (cancelled)
|
||||
HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
|
||||
} while (cancelled);
|
||||
@ -1159,12 +1152,6 @@ GlobalHelperThreadState::maxIonCompilationThreads() const
|
||||
return threadCount;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxUnpausedIonCompilationThreads() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxWasmCompilationThreads() const
|
||||
{
|
||||
@ -1276,6 +1263,8 @@ GlobalHelperThreadState::canStartPromiseHelperTask(const AutoLockHelperThreadSta
|
||||
static bool
|
||||
IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second)
|
||||
{
|
||||
// Return true if priority(first) > priority(second).
|
||||
//
|
||||
// This method can return whatever it wants, though it really ought to be a
|
||||
// total order. The ordering is allowed to race (change on the fly), however.
|
||||
|
||||
@ -1306,14 +1295,10 @@ GlobalHelperThreadState::canStartIonFreeTask(const AutoLockHelperThreadState& lo
|
||||
}
|
||||
|
||||
jit::IonBuilder*
|
||||
GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
|
||||
bool remove /* = false */)
|
||||
GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
auto& worklist = ionWorklist(lock);
|
||||
if (worklist.empty()) {
|
||||
MOZ_ASSERT(!remove);
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(!worklist.empty());
|
||||
|
||||
// Get the highest priority IonBuilder which has not started compilation yet.
|
||||
size_t index = 0;
|
||||
@ -1321,84 +1306,12 @@ GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperTh
|
||||
if (IonBuilderHasHigherPriority(worklist[i], worklist[index]))
|
||||
index = i;
|
||||
}
|
||||
|
||||
jit::IonBuilder* builder = worklist[index];
|
||||
if (remove)
|
||||
worklist.erase(&worklist[index]);
|
||||
worklist.erase(&worklist[index]);
|
||||
return builder;
|
||||
}
|
||||
|
||||
HelperThread*
|
||||
GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold(
|
||||
const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
// Get the lowest priority IonBuilder which has started compilation and
|
||||
// isn't paused, unless there are still fewer than the maximum number of
|
||||
// such builders permitted.
|
||||
size_t numBuilderThreads = 0;
|
||||
HelperThread* thread = nullptr;
|
||||
for (auto& thisThread : *threads) {
|
||||
if (thisThread.ionBuilder() && !thisThread.pause) {
|
||||
numBuilderThreads++;
|
||||
if (!thread ||
|
||||
IonBuilderHasHigherPriority(thread->ionBuilder(), thisThread.ionBuilder()))
|
||||
{
|
||||
thread = &thisThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numBuilderThreads < maxUnpausedIonCompilationThreads())
|
||||
return nullptr;
|
||||
return thread;
|
||||
}
|
||||
|
||||
HelperThread*
|
||||
GlobalHelperThreadState::highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
// Get the highest priority IonBuilder which has started compilation but
|
||||
// which was subsequently paused.
|
||||
HelperThread* thread = nullptr;
|
||||
for (auto& thisThread : *threads) {
|
||||
if (thisThread.pause) {
|
||||
// Currently, only threads with IonBuilders can be paused.
|
||||
MOZ_ASSERT(thisThread.ionBuilder());
|
||||
if (!thread ||
|
||||
IonBuilderHasHigherPriority(thisThread.ionBuilder(), thread->ionBuilder()))
|
||||
{
|
||||
thread = &thisThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalHelperThreadState::pendingIonCompileHasSufficientPriority(
|
||||
const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
// Can't compile anything if there are no scripts to compile.
|
||||
if (!canStartIonCompile(lock))
|
||||
return false;
|
||||
|
||||
// Count the number of threads currently compiling scripts, and look for
|
||||
// the thread with the lowest priority.
|
||||
HelperThread* lowestPriorityThread = lowestPriorityUnpausedIonCompileAtThreshold(lock);
|
||||
|
||||
// If the number of threads building scripts is less than the maximum, the
|
||||
// compilation can start immediately.
|
||||
if (!lowestPriorityThread)
|
||||
return true;
|
||||
|
||||
// If there is a builder in the worklist with higher priority than some
|
||||
// builder currently being compiled, then that current compilation can be
|
||||
// paused, so allow the compilation.
|
||||
if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(lock),
|
||||
lowestPriorityThread->ionBuilder()))
|
||||
return true;
|
||||
|
||||
// Compilation will have to wait until one of the active compilations finishes.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalHelperThreadState::canStartParseTask(const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
@ -1941,22 +1854,9 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
|
||||
|
||||
// Find the IonBuilder in the worklist with the highest priority, and
|
||||
// remove it from the worklist.
|
||||
jit::IonBuilder* builder =
|
||||
HelperThreadState().highestPriorityPendingIonCompile(locked, /* remove = */ true);
|
||||
|
||||
// If there are now too many threads with active IonBuilders, indicate to
|
||||
// the one with the lowest priority that it should pause. Note that due to
|
||||
// builder priorities changing since pendingIonCompileHasSufficientPriority
|
||||
// was called, the builder we are pausing may actually be higher priority
|
||||
// than the one we are about to start. Oh well.
|
||||
HelperThread* other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold(locked);
|
||||
if (other) {
|
||||
MOZ_ASSERT(other->ionBuilder() && !other->pause);
|
||||
other->pause = true;
|
||||
}
|
||||
jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile(locked);
|
||||
|
||||
currentTask.emplace(builder);
|
||||
builder->setPauseFlag(&pause);
|
||||
|
||||
JSRuntime* rt = builder->script()->compartment()->runtimeFromAnyThread();
|
||||
|
||||
@ -1992,32 +1892,9 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
|
||||
target->requestInterrupt(JSContext::RequestInterruptCanWait);
|
||||
|
||||
currentTask.reset();
|
||||
pause = false;
|
||||
|
||||
// Notify the active thread in case it is waiting for the compilation to finish.
|
||||
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
|
||||
|
||||
// When finishing Ion compilation jobs, we can start unpausing compilation
|
||||
// threads that were paused to restrict the number of active compilations.
|
||||
// Only unpause one at a time, to make sure we don't exceed the restriction.
|
||||
// Since threads are currently only paused for Ion compilations, this
|
||||
// strategy will eventually unpause all paused threads, regardless of how
|
||||
// many there are, since each thread we unpause will eventually finish and
|
||||
// end up back here.
|
||||
if (HelperThread* other = HelperThreadState().highestPriorityPausedIonCompile(locked)) {
|
||||
MOZ_ASSERT(other->ionBuilder() && other->pause);
|
||||
|
||||
// Only unpause the other thread if there isn't a higher priority
|
||||
// builder which this thread or another can start on.
|
||||
jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile(locked);
|
||||
if (!builder || IonBuilderHasHigherPriority(other->ionBuilder(), builder)) {
|
||||
other->pause = false;
|
||||
|
||||
// Notify all paused threads, to make sure the one we just
|
||||
// unpaused wakes up.
|
||||
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, locked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -2048,20 +1925,6 @@ js::CurrentHelperThread()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
js::PauseCurrentHelperThread()
|
||||
{
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
|
||||
|
||||
HelperThread* thread = CurrentHelperThread();
|
||||
MOZ_ASSERT(thread);
|
||||
|
||||
AutoLockHelperThreadState lock;
|
||||
while (thread->pause)
|
||||
HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE);
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::addPendingCompileError(js::CompileError** error)
|
||||
{
|
||||
@ -2345,7 +2208,7 @@ HelperThread::threadLoop()
|
||||
task = js::THREAD_TYPE_GCPARALLEL;
|
||||
} else if (HelperThreadState().canStartGCHelperTask(lock)) {
|
||||
task = js::THREAD_TYPE_GCHELPER;
|
||||
} else if (HelperThreadState().pendingIonCompileHasSufficientPriority(lock)) {
|
||||
} else if (HelperThreadState().canStartIonCompile(lock)) {
|
||||
task = js::THREAD_TYPE_ION;
|
||||
} else if (HelperThreadState().canStartWasmCompile(lock, wasm::CompileMode::Tier1)) {
|
||||
task = js::THREAD_TYPE_WASM;
|
||||
|
@ -143,7 +143,6 @@ class GlobalHelperThreadState
|
||||
|
||||
public:
|
||||
size_t maxIonCompilationThreads() const;
|
||||
size_t maxUnpausedIonCompilationThreads() const;
|
||||
size_t maxWasmCompilationThreads() const;
|
||||
size_t maxWasmTier2GeneratorThreads() const;
|
||||
size_t maxParseThreads() const;
|
||||
@ -173,10 +172,6 @@ class GlobalHelperThreadState
|
||||
// make progress, ie, a work item has been enqueued and an idle helper
|
||||
// thread may pick up up the work item and perform it.
|
||||
PRODUCER,
|
||||
|
||||
// For notifying threads doing work which are paused that they may be
|
||||
// able to resume making progress.
|
||||
PAUSE
|
||||
};
|
||||
|
||||
void wait(AutoLockHelperThreadState& locked, CondVar which,
|
||||
@ -280,16 +275,7 @@ class GlobalHelperThreadState
|
||||
void scheduleCompressionTasks(const AutoLockHelperThreadState&);
|
||||
|
||||
public:
|
||||
// Unlike the public methods above, the value returned by this method can
|
||||
// change over time, even if the helper thread state lock is held
|
||||
// throughout.
|
||||
bool pendingIonCompileHasSufficientPriority(const AutoLockHelperThreadState& lock);
|
||||
|
||||
jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
|
||||
bool remove = false);
|
||||
HelperThread* lowestPriorityUnpausedIonCompileAtThreshold(
|
||||
const AutoLockHelperThreadState& lock);
|
||||
HelperThread* highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock);
|
||||
jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock);
|
||||
|
||||
template <
|
||||
typename F,
|
||||
@ -335,13 +321,11 @@ class GlobalHelperThreadState
|
||||
/* Condvars for threads waiting/notifying each other. */
|
||||
js::ConditionVariable consumerWakeup;
|
||||
js::ConditionVariable producerWakeup;
|
||||
js::ConditionVariable pauseWakeup;
|
||||
|
||||
js::ConditionVariable& whichWakeup(CondVar which) {
|
||||
switch (which) {
|
||||
case CONSUMER: return consumerWakeup;
|
||||
case PRODUCER: return producerWakeup;
|
||||
case PAUSE: return pauseWakeup;
|
||||
default: MOZ_CRASH("Invalid CondVar in |whichWakeup|");
|
||||
}
|
||||
}
|
||||
@ -376,13 +360,6 @@ struct HelperThread
|
||||
*/
|
||||
bool terminate;
|
||||
|
||||
/*
|
||||
* Indicate to a thread that it should pause execution. This is only
|
||||
* written with the helper thread state lock held, but may be read from
|
||||
* without the lock held.
|
||||
*/
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> pause;
|
||||
|
||||
/* The current task being executed by this thread, if any. */
|
||||
mozilla::Maybe<HelperTaskUnion> currentTask;
|
||||
|
||||
@ -472,10 +449,6 @@ SetFakeCPUCount(size_t count);
|
||||
HelperThread*
|
||||
CurrentHelperThread();
|
||||
|
||||
// Pause the current thread until it's pause flag is unset.
|
||||
void
|
||||
PauseCurrentHelperThread();
|
||||
|
||||
// Enqueues a wasm compilation task.
|
||||
bool
|
||||
StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode);
|
||||
|
@ -23,7 +23,6 @@
|
||||
_(InlinedScripts) \
|
||||
_(IonAnalysis) \
|
||||
_(IonCompilation) \
|
||||
_(IonCompilationPaused) \
|
||||
_(IonLinking) \
|
||||
_(IonMonkey) \
|
||||
_(IrregexpCompile) \
|
||||
|
Loading…
Reference in New Issue
Block a user