Bug 1373414 - Backout wasm work stealing on JS helper threads. r=shu

--HG--
extra : rebase_source : 8b1dbd5f5885d41c281da137496ac5e268f4029c
extra : source : 55393d7d4f5d8a0d6258cc3035f418a05ba40aea
This commit is contained in:
Lars T Hansen 2017-07-07 16:03:39 -07:00
Родитель b43f3b0d25
Коммит 814a1042c6
4 изменённых файлов: 16 добавлений и 66 удалений

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

@ -1057,16 +1057,12 @@ GlobalHelperThreadState::maxGCParallelThreads() const
} }
bool bool
GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock, GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock)
bool assumeThreadAvailable)
{ {
// Don't execute an wasm job if an earlier one failed. // Don't execute an wasm job if an earlier one failed.
if (wasmWorklist(lock).empty() || numWasmFailedJobs) if (wasmWorklist(lock).empty() || numWasmFailedJobs)
return false; return false;
if (assumeThreadAvailable)
return true;
// Honor the maximum allowed threads to compile wasm jobs at once, // Honor the maximum allowed threads to compile wasm jobs at once,
// to avoid oversaturating the machine. // to avoid oversaturating the machine.
if (!checkTaskThreadLimit<wasm::CompileTask*>(maxWasmCompilationThreads())) if (!checkTaskThreadLimit<wasm::CompileTask*>(maxWasmCompilationThreads()))
@ -1668,9 +1664,9 @@ HelperThread::ThreadMain(void* arg)
} }
void void
HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked, bool assumeThreadAvailable) HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
{ {
MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked, assumeThreadAvailable)); MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked));
MOZ_ASSERT(idle()); MOZ_ASSERT(idle());
currentTask.emplace(HelperThreadState().wasmWorklist(locked).popCopy()); currentTask.emplace(HelperThreadState().wasmWorklist(locked).popCopy());
@ -1698,33 +1694,6 @@ HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked, bool assumeT
currentTask.reset(); currentTask.reset();
} }
bool
HelperThread::handleWasmIdleWorkload(AutoLockHelperThreadState& locked)
{
// Perform wasm compilation work on a HelperThread that is running
// ModuleGenerator instead of blocking while other compilation threads
// finish. This removes a source of deadlocks, as putting all threads to
// work guarantees forward progress for compilation.
// The current thread has already been accounted for, so don't guard on
// thread subscription when checking whether we can do work.
if (HelperThreadState().canStartWasmCompile(locked, /*assumeThreadAvailable=*/ true)) {
HelperTaskUnion oldTask = currentTask.value();
currentTask.reset();
js::oom::ThreadType oldType = (js::oom::ThreadType)js::oom::GetThreadType();
js::oom::SetThreadType(js::oom::THREAD_TYPE_WASM);
handleWasmWorkload(locked, /*assumeThreadAvailable=*/ true);
js::oom::SetThreadType(oldType);
currentTask.emplace(oldTask);
return true;
}
return false;
}
void void
HelperThread::handlePromiseTaskWorkload(AutoLockHelperThreadState& locked) HelperThread::handlePromiseTaskWorkload(AutoLockHelperThreadState& locked)
{ {

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

@ -224,8 +224,7 @@ class GlobalHelperThreadState
return gcParallelWorklist_; return gcParallelWorklist_;
} }
bool canStartWasmCompile(const AutoLockHelperThreadState& lock, bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
bool assumeThreadAvailable = false);
bool canStartPromiseTask(const AutoLockHelperThreadState& lock); bool canStartPromiseTask(const AutoLockHelperThreadState& lock);
bool canStartIonCompile(const AutoLockHelperThreadState& lock); bool canStartIonCompile(const AutoLockHelperThreadState& lock);
bool canStartIonFreeTask(const AutoLockHelperThreadState& lock); bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
@ -388,13 +387,6 @@ struct HelperThread
return maybeCurrentTaskAs<wasm::CompileTask*>(); return maybeCurrentTaskAs<wasm::CompileTask*>();
} }
/*
* Perform wasm compilation work on behalf of a thread that is running a
* wasm ModuleGenerator and would otherwise block waiting for other
* compilation threads. Return true if work was performed, otherwise false.
*/
bool handleWasmIdleWorkload(AutoLockHelperThreadState& locked);
/* Any source being parsed/emitted on this thread. */ /* Any source being parsed/emitted on this thread. */
ParseTask* parseTask() { ParseTask* parseTask() {
return maybeCurrentTaskAs<ParseTask*>(); return maybeCurrentTaskAs<ParseTask*>();
@ -429,7 +421,7 @@ struct HelperThread
return nullptr; return nullptr;
} }
void handleWasmWorkload(AutoLockHelperThreadState& locked, bool assumeThreadAvailable = false); void handleWasmWorkload(AutoLockHelperThreadState& locked);
void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked); void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked);
void handleIonWorkload(AutoLockHelperThreadState& locked); void handleIonWorkload(AutoLockHelperThreadState& locked);
void handleIonFreeWorkload(AutoLockHelperThreadState& locked); void handleIonFreeWorkload(AutoLockHelperThreadState& locked);

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

@ -61,7 +61,6 @@ ModuleGenerator::ModuleGenerator(UniqueChars* error)
outstanding_(0), outstanding_(0),
currentTask_(nullptr), currentTask_(nullptr),
batchedBytecode_(0), batchedBytecode_(0),
maybeHelperThread_(CurrentHelperThread()),
activeFuncDef_(nullptr), activeFuncDef_(nullptr),
startedFuncDefs_(false), startedFuncDefs_(false),
finishedFuncDefs_(false), finishedFuncDefs_(false),
@ -298,17 +297,7 @@ ModuleGenerator::finishOutstandingTask()
break; break;
} }
// If we're on a helper thread then attempt to do some work. This HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
// avoids a source of deadlocks, as putting all threads to work
// guarantees forward progress for compilation.
if (!maybeHelperThread_ || !maybeHelperThread_->handleWasmIdleWorkload(lock)) {
// Other threads are working on the remaining task(s) and will
// notify us when that work is complete.
MOZ_ASSERT(outstanding_ > 0);
MOZ_ASSERT_IF(maybeHelperThread_, HelperThreadState().wasmWorklist(lock).empty());
HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
}
} }
} }
@ -883,17 +872,18 @@ ModuleGenerator::startFuncDefs()
MOZ_ASSERT(!finishedFuncDefs_); MOZ_ASSERT(!finishedFuncDefs_);
// The wasmCompilationInProgress atomic ensures that there is only one // The wasmCompilationInProgress atomic ensures that there is only one
// parallel compilation in progress at a time. This restriction can be // parallel compilation in progress at a time. In the special case of
// lifted, but it will be somewhat desirable to keep it when tiered // asm.js, where the ModuleGenerator itself can be on a helper thread, this
// compilation is introduced (and tier-2 code for one module can be compiled // avoids the possibility of deadlock since at most 1 helper thread will be
// in parallel with the tier-1 code for the next module). // blocking on other helper threads and there are always >1 helper threads.
// // With wasm, this restriction could be relaxed by moving the worklist state
// Deadlocks are avoided by guaranteeing the forward progress of // out of HelperThreadState since each independent compilation needs its own
// compilation, in particular, by having the ModuleGenerator thread (in the // worklist pair. Alternatively, the deadlock could be avoided by having the
// case of asm.js and future tiered compilation) make progress on // ModuleGenerator thread make progress (on compile tasks) instead of
// compilation and not simply wait for other helper threads to finish. // blocking.
GlobalHelperThreadState& threads = HelperThreadState(); GlobalHelperThreadState& threads = HelperThreadState();
MOZ_ASSERT(threads.threadCount > 1);
uint32_t numTasks; uint32_t numTasks;
if (CanUseExtraThreads() && if (CanUseExtraThreads() &&

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

@ -244,7 +244,6 @@ class MOZ_STACK_CLASS ModuleGenerator
UniqueFuncBytesVector freeFuncBytes_; UniqueFuncBytesVector freeFuncBytes_;
CompileTask* currentTask_; CompileTask* currentTask_;
uint32_t batchedBytecode_; uint32_t batchedBytecode_;
HelperThread* maybeHelperThread_;
// Assertions // Assertions
DebugOnly<FunctionGenerator*> activeFuncDef_; DebugOnly<FunctionGenerator*> activeFuncDef_;