Bug 1398140 - Remove Ion helper thread pausing mechanism. r=luke

This commit is contained in:
Jan de Mooij 2017-09-11 16:53:38 +02:00
parent 89f1957239
commit 85296b8b20
5 changed files with 9 additions and 185 deletions

View File

@ -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_;

View File

@ -28,7 +28,6 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
graph_(graph),
offThreadStatus_(Ok()),
abortedPreliminaryGroups_(*alloc_),
pauseBuild_(nullptr),
cancelBuild_(false),
wasmMaxStackArgBytes_(0),
needsOverrecursedCheck_(false),

View File

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

View File

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

View File

@ -23,7 +23,6 @@
_(InlinedScripts) \
_(IonAnalysis) \
_(IonCompilation) \
_(IonCompilationPaused) \
_(IonLinking) \
_(IonMonkey) \
_(IrregexpCompile) \