mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
ported from UXP: Issue #3075 - Backport bug 1398140 - Remove the Ion helper thread pausing (6e638a5d)
This commit is contained in:
@@ -113,21 +113,12 @@ class MIRGenerator
|
||||
|
||||
// Whether the main 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();
|
||||
}
|
||||
@@ -173,7 +164,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_;
|
||||
|
||||
@@ -26,7 +26,6 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
|
||||
graph_(graph),
|
||||
offThreadStatus_(Ok()),
|
||||
abortedPreliminaryGroups_(*alloc_),
|
||||
pauseBuild_(nullptr),
|
||||
cancelBuild_(false),
|
||||
wasmMaxStackArgBytes_(0),
|
||||
performsCall_(false),
|
||||
|
||||
+22
-156
@@ -71,7 +71,11 @@ static size_t
|
||||
ThreadCountForCPUCount(size_t cpuCount)
|
||||
{
|
||||
// Create additional threads on top of the number of cores available, to
|
||||
// provide some excess capacity in case threads pause each other.
|
||||
// provide some excess capacity in case threads pause each other and for mixed
|
||||
// helper-thread workloads.
|
||||
// Note that cpuCount here is the number of logical processors and threadCount
|
||||
// calculated here just adds some extra capacity on top. Use threadCount
|
||||
// with care as it may end up deadlocking.
|
||||
static const uint32_t EXCESS_THREADS = 4;
|
||||
return cpuCount + EXCESS_THREADS;
|
||||
}
|
||||
@@ -210,21 +214,14 @@ js::CancelOffThreadIonCompile(CompilationSelector selector, bool discardLazyLink
|
||||
bool cancelled;
|
||||
do {
|
||||
cancelled = false;
|
||||
bool unpaused = false;
|
||||
for (auto& helper : *HelperThreadState().threads) {
|
||||
if (helper.ionBuilder() &&
|
||||
CompiledScriptMatches(selector, helper.ionBuilder()->script()))
|
||||
{
|
||||
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);
|
||||
@@ -920,12 +917,6 @@ GlobalHelperThreadState::maxIonCompilationThreads() const
|
||||
return threadCount;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxUnpausedIonCompilationThreads() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxWasmCompilationThreads() const
|
||||
{
|
||||
@@ -991,6 +982,8 @@ GlobalHelperThreadState::canStartPromiseTask(const AutoLockHelperThreadState& lo
|
||||
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.
|
||||
|
||||
@@ -1021,14 +1014,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;
|
||||
@@ -1037,83 +1026,10 @@ GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperTh
|
||||
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)
|
||||
{
|
||||
@@ -1550,22 +1466,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();
|
||||
|
||||
@@ -1587,7 +1490,6 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
|
||||
|
||||
FinishOffThreadIonCompile(builder, locked);
|
||||
currentTask.reset();
|
||||
pause = false;
|
||||
|
||||
// Ping the main thread so that the compiled code can be incorporated
|
||||
// at the next interrupt callback. Don't interrupt Ion code for this, as
|
||||
@@ -1597,43 +1499,6 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
|
||||
|
||||
// Notify the main 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HelperThread*
|
||||
CurrentHelperThread()
|
||||
{
|
||||
auto threadId = ThisThread::GetId();
|
||||
HelperThread* thread = nullptr;
|
||||
for (auto& thisThread : *HelperThreadState().threads) {
|
||||
if (thisThread.thread.isSome() && threadId == thisThread.thread->get_id()) {
|
||||
thread = &thisThread;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(thread);
|
||||
return thread;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1651,17 +1516,18 @@ HelperThread::handleIonFreeWorkload(AutoLockHelperThreadState& locked)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::PauseCurrentHelperThread()
|
||||
HelperThread*
|
||||
js::CurrentHelperThread()
|
||||
{
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
|
||||
if (!HelperThreadState().threads)
|
||||
return nullptr;
|
||||
|
||||
HelperThread* thread = CurrentHelperThread();
|
||||
|
||||
AutoLockHelperThreadState lock;
|
||||
while (thread->pause)
|
||||
HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE);
|
||||
auto threadId = ThisThread::GetId();
|
||||
for (auto& thisThread : *HelperThreadState().threads) {
|
||||
if (thisThread.thread.isSome() && threadId == thisThread.thread->get_id())
|
||||
return &thisThread;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1956,7 +1822,7 @@ HelperThread::threadLoop()
|
||||
task = js::oom::THREAD_TYPE_GCPARALLEL;
|
||||
else if (HelperThreadState().canStartGCHelperTask(lock))
|
||||
task = js::oom::THREAD_TYPE_GCHELPER;
|
||||
else if (HelperThreadState().pendingIonCompileHasSufficientPriority(lock))
|
||||
else if (HelperThreadState().canStartIonCompile(lock))
|
||||
task = js::oom::THREAD_TYPE_ION;
|
||||
else if (HelperThreadState().canStartWasmCompile(lock))
|
||||
task = js::oom::THREAD_TYPE_WASM;
|
||||
|
||||
@@ -118,7 +118,6 @@ class GlobalHelperThreadState
|
||||
|
||||
public:
|
||||
size_t maxIonCompilationThreads() const;
|
||||
size_t maxUnpausedIonCompilationThreads() const;
|
||||
size_t maxWasmCompilationThreads() const;
|
||||
size_t maxParseThreads() const;
|
||||
size_t maxCompressionThreads() const;
|
||||
@@ -140,10 +139,6 @@ class GlobalHelperThreadState
|
||||
|
||||
// For notifying threads doing work that they may be able to make progress.
|
||||
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,
|
||||
@@ -211,15 +206,7 @@ class GlobalHelperThreadState
|
||||
bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
|
||||
bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
|
||||
|
||||
// Unlike the 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);
|
||||
|
||||
uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&) {
|
||||
uint32_t n = numWasmFailedJobs;
|
||||
@@ -286,13 +273,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|");
|
||||
}
|
||||
}
|
||||
@@ -319,13 +304,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<mozilla::Variant<jit::IonBuilder*,
|
||||
wasm::CompileTask*,
|
||||
@@ -412,9 +390,9 @@ EnsureHelperThreadsInitialized();
|
||||
void
|
||||
SetFakeCPUCount(size_t count);
|
||||
|
||||
// Pause the current thread until it's pause flag is unset.
|
||||
void
|
||||
PauseCurrentHelperThread();
|
||||
// Get the current helper thread, or null.
|
||||
HelperThread*
|
||||
CurrentHelperThread();
|
||||
|
||||
// Enqueues a wasm compilation task.
|
||||
bool
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
_(InlinedScripts) \
|
||||
_(IonAnalysis) \
|
||||
_(IonCompilation) \
|
||||
_(IonCompilationPaused) \
|
||||
_(IonLinking) \
|
||||
_(IonMonkey) \
|
||||
_(IrregexpCompile) \
|
||||
|
||||
Reference in New Issue
Block a user