From 64a379ef892a7566db246af5c7bb0d7a19b76c48 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Thu, 22 Nov 2012 10:02:18 -0500 Subject: [PATCH] Add --thread-count=N to shell, use at most one core for off thread compilation, disallow off thread compilation during IGC, bug 813559. r=dvander --- js/src/ion/Ion.cpp | 8 +++++++- js/src/jsapi.cpp | 3 ++- js/src/jscntxt.h | 19 +++++++++++++++++++ js/src/jsworkers.cpp | 20 ++++++++++++++++++-- js/src/jsworkers.h | 2 ++ js/src/shell/js.cpp | 15 +++++++++++++-- 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index 697ac1754f99..e630426c9796 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -1130,7 +1130,13 @@ SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph, } builder->clearForBackEnd(); - if (js_IonOptions.parallelCompilation && OffThreadCompilationAvailable(cx)) { + // Try to compile the script off thread, if possible. Compilation cannot be + // performed off thread during an incremental GC, as doing so may trip + // incremental read barriers. + if (js_IonOptions.parallelCompilation && + OffThreadCompilationAvailable(cx) && + !cx->compartment->needsBarrier()) + { builder->script()->ion = ION_COMPILING_SCRIPT; if (!StartOffThreadIonCompile(cx, builder)) { diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 13f08d7363f0..2d95b75aed53 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -874,7 +874,8 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) ionPcScriptCache(NULL), threadPool(this), ionReturnOverride_(MagicValue(JS_ARG_POISON)), - useHelperThreads_(useHelperThreads) + useHelperThreads_(useHelperThreads), + requestedHelperThreadCount(-1) { /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&debuggerList); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 6df350927e2f..94aff2407d4d 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1176,13 +1176,32 @@ struct JSRuntime : js::RuntimeFriendFields size_t sizeOfExplicitNonHeap(); private: + JSUseHelperThreads useHelperThreads_; + int32_t requestedHelperThreadCount; + public: + bool useHelperThreads() const { #ifdef JS_THREADSAFE return useHelperThreads_ == JS_USE_HELPER_THREADS; #else return false; +#endif + } + + void requestHelperThreadCount(size_t count) { + requestedHelperThreadCount = count; + } + + /* Number of helper threads which should be created for this runtime. */ + size_t helperThreadCount() const { +#ifdef JS_THREADSAFE + if (requestedHelperThreadCount < 0) + return js::GetCPUCount() - 1; + return requestedHelperThreadCount; +#else + return 0; #endif } }; diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 0572911c7b1f..d1fd28a6ec4c 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -143,7 +143,7 @@ WorkerThreadState::init(JSRuntime *rt) if (!helperWakeup) return false; - numThreads = GetCPUCount() - 1; + numThreads = rt->helperThreadCount(); threads = (WorkerThread*) rt->calloc_(sizeof(WorkerThread) * numThreads); if (!threads) { @@ -250,6 +250,22 @@ WorkerThreadState::notifyAll(CondVar which) PR_NotifyAllCondVar((which == MAIN) ? mainWakeup : helperWakeup); } +bool +WorkerThreadState::canStartIonCompile() +{ + // A worker thread can begin an Ion compilation if (a) there is some script + // which is waiting to be compiled, and (b) no other worker thread is + // currently compiling a script. The latter condition ensures that two + // compilations cannot simultaneously occur. + if (ionWorklist.empty()) + return false; + for (size_t i = 0; i < numThreads; i++) { + if (threads[i].ionBuilder) + return false; + } + return true; +} + void WorkerThread::destroy() { @@ -289,7 +305,7 @@ WorkerThread::threadLoop() while (true) { JS_ASSERT(!ionBuilder); - while (state.ionWorklist.empty()) { + while (!state.canStartIonCompile()) { if (terminate) { state.unlock(); return; diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h index 9994b394cb7c..7cfba16f10f8 100644 --- a/js/src/jsworkers.h +++ b/js/src/jsworkers.h @@ -59,6 +59,8 @@ class WorkerThreadState void notify(CondVar which); void notifyAll(CondVar which); + bool canStartIonCompile(); + private: /* diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 58ba4813db85..8d0648a63e98 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -40,6 +40,7 @@ #include "jsscript.h" #include "jstypedarray.h" #include "jstypedarrayinlines.h" +#include "jsworkers.h" #include "jsxml.h" #include "jsperf.h" @@ -4748,6 +4749,12 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) if (op->getBoolOption('D')) enableDisassemblyDumps = true; +#ifdef JS_THREADSAFE + int32_t threadCount = op->getIntOption("thread-count"); + if (threadCount >= 0) + cx->runtime->requestHelperThreadCount(threadCount); +#endif /* JS_THREADSAFE */ + #if defined(JS_ION) if (op->getBoolOption("no-ion")) { enableIon = false; @@ -4832,8 +4839,8 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) #ifdef JS_THREADSAFE if (const char *str = op->getStringOption("ion-parallel-compile")) { if (strcmp(str, "on") == 0) { - if (GetCPUCount() <= 1) { - fprintf(stderr, "Parallel compilation not available on single core machines"); + if (cx->runtime->helperThreadCount() == 0) { + fprintf(stderr, "Parallel compilation not available without helper threads"); return EXIT_FAILURE; } ion::js_IonOptions.parallelCompilation = true; @@ -5025,6 +5032,10 @@ main(int argc, char **argv, char **envp) || !op.addOptionalMultiStringArg("scriptArgs", "String arguments to bind as |arguments| in the " "shell's global") +#ifdef JS_THREADSAFE + || !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads " + "(default: # of cores - 1)", -1) +#endif || !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)") || !op.addBoolOption('\0', "no-ion", "Disable IonMonkey") || !op.addStringOption('\0', "ion-gvn", "[mode]",