Bug 1539270 Part 1: Add HelperThreadPool & HelperThreadTaskHandler classes and their initialization/shutdown process to manage an nsThreadPool r=mccr8,froydnj
authorKristen Wright <kwright@mozilla.com>
Mon, 24 Jun 2019 22:29:18 +0000
changeset 542818 84bba101c4f43a39dad3388c93080fb4d9cca804
parent 542817 11459fc963acca1af7f6fc9da8a5a97b0b700257
child 542819 abacb77a97bbcfb54915aedd34ef7aefafdb0e78
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, froydnj
bugs1539270
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1539270 Part 1: Add HelperThreadPool & HelperThreadTaskHandler classes and their initialization/shutdown process to manage an nsThreadPool r=mccr8,froydnj Added HelperThreadPool & HelperThreadTaskHandler classes to hold and manage an nsThreadPool. Initialized thread pool in XPCJSRuntime. Differential Revision: https://phabricator.services.mozilla.com/D27817
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCJSThreadPool.h
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/UniquePtr.h"
 
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "XPCWrapper.h"
 #include "XPCJSMemoryReporter.h"
+#include "XPCJSThreadPool.h"
 #include "XrayWrapper.h"
 #include "WrapperFactory.h"
 #include "mozJSComponentLoader.h"
 #include "nsAutoPtr.h"
 #include "nsNetUtil.h"
 
 #include "nsExceptionHandler.h"
 #include "nsIMemoryInfoDumper.h"
@@ -26,16 +27,17 @@
 #include "nsIObserverService.h"
 #include "nsIDebug2.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "nsIRunnable.h"
 #include "nsIPlatformInfo.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
+#include "nsThreadPool.h"
 #include "nsWindowSizes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "nsContentUtils.h"
@@ -1118,28 +1120,40 @@ size_t CompartmentPrivate::SizeOfIncludi
 /***************************************************************************/
 
 void XPCJSRuntime::SystemIsBeingShutDown() {
   // We don't want to track wrapped JS roots after this point since we're
   // making them !IsValid anyway through SystemIsBeingShutDown.
   mWrappedJSRoots = nullptr;
 }
 
+StaticAutoPtr<HelperThreadPool> gHelperThreads;
+
+void InitializeHelperThreadPool() { gHelperThreads = new HelperThreadPool(); }
+
+void DispatchOffThreadTask(RunnableTask* task) {
+  gHelperThreads->Dispatch(MakeAndAddRef<HelperThreadTaskHandler>(task));
+}
+
 void XPCJSRuntime::Shutdown(JSContext* cx) {
   // This destructor runs before ~CycleCollectedJSContext, which does the
   // actual JS_DestroyContext() call. But destroying the context triggers
   // one final GC, which can call back into the context with various
   // callbacks if we aren't careful. Null out the relevant callbacks.
   JS_RemoveFinalizeCallback(cx, FinalizeCallback);
   JS_RemoveWeakPointerZonesCallback(cx, WeakPointerZonesCallback);
   JS_RemoveWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback);
   xpc_DelocalizeRuntime(JS_GetRuntime(cx));
 
   JS::SetGCSliceCallback(cx, mPrevGCSliceCallback);
 
+  // Shut down the helper threads
+  gHelperThreads->Shutdown();
+  gHelperThreads = nullptr;
+
   // clean up and destroy maps...
   mWrappedJSMap->ShutdownMarker();
   delete mWrappedJSMap;
   mWrappedJSMap = nullptr;
 
   delete mIID2NativeInterfaceMap;
   mIID2NativeInterfaceMap = nullptr;
 
@@ -3066,16 +3080,19 @@ void XPCJSRuntime::Initialize(JSContext*
   JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
   JS_SetSetUseCounterCallback(cx, SetUseCounterCallback);
   js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
   js::SetXrayJitInfo(&gXrayJitInfo);
   JS::SetProcessLargeAllocationFailureCallback(
       OnLargeAllocationFailureCallback);
   JS::SetProcessBuildIdOp(GetBuildId);
 
+  // Initialize a helper thread pool for JS offthread tasks.
+  InitializeHelperThreadPool();
+
   // The JS engine needs to keep the source code around in order to implement
   // Function.prototype.toSource(). It'd be nice to not have to do this for
   // chrome code and simply stub out requests for source on it. Life is not so
   // easy, unfortunately. Nobody relies on chrome toSource() working in core
   // browser code, but chrome tests use it. The worst offenders are addons,
   // which like to monkeypatch chrome functions by calling toSource() on them
   // and using regular expressions to modify them. We avoid keeping most browser
   // JS source code in memory by setting LAZY_SOURCE on JS::CompileOptions when
@@ -3325,8 +3342,30 @@ JSObject* XPCJSRuntime::LoaderGlobal() {
     dom::AutoJSAPI jsapi;
     jsapi.Init();
 
     mLoaderGlobal = loader->GetSharedGlobal(jsapi.cx());
     MOZ_RELEASE_ASSERT(!JS_IsExceptionPending(jsapi.cx()));
   }
   return mLoaderGlobal;
 }
+
+uint32_t GetAndClampCPUCount() {
+  // See HelperThreads.cpp for why we want between 2-8 threads
+  int32_t proc = GetNumberOfProcessors();
+  if (proc < 2) {
+    return 2;
+  }
+  return std::min(proc, 8);
+}
+nsresult HelperThreadPool::Dispatch(
+    already_AddRefed<HelperThreadTaskHandler> aRunnable) {
+  mPool->Dispatch(std::move(aRunnable), NS_DISPATCH_NORMAL);
+  return NS_OK;
+}
+
+HelperThreadPool::HelperThreadPool() {
+  mPool = new nsThreadPool();
+  mPool->SetName(NS_LITERAL_CSTRING("JSHelperThreads"));
+  mPool->SetThreadLimit(GetAndClampCPUCount());
+}
+
+void HelperThreadPool::Shutdown() { mPool->Shutdown(); }
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/src/XPCJSThreadPool.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_JSThreadPool_h
+#define mozilla_JSThreadPool_h
+
+#include "nsIThreadPool.h"
+#include "js/Utility.h"
+
+namespace mozilla {
+/*
+ * Since XPCOM thread pools dispatch nsIRunnable*, we want a way to take the
+ * specific job that JS wants to dispatch offthread, and run it via an
+ * nsIRunnable(). RunnableTasks should self-destroy.
+ */
+class HelperThreadTaskHandler : public Runnable {
+ public:
+  NS_IMETHOD Run() override {
+    mOffThreadTask->runTask();
+    mOffThreadTask = nullptr;
+    return NS_OK;
+  }
+  explicit HelperThreadTaskHandler(RunnableTask* task)
+      : Runnable("HelperThreadTaskHandler"), mOffThreadTask(task) {}
+
+ private:
+  ~HelperThreadTaskHandler() = default;
+  RunnableTask* mOffThreadTask;
+};
+
+/*
+ * HelperThreadPool is a thread pool infrastructure for JS offthread tasks. It
+ * holds the actual instance of a thread pool that we instantiate. The intention
+ * is to have a way to manage some of the things GlobalHelperThreadState does
+ * independently of nsThreadPool.
+ */
+class HelperThreadPool {
+ public:
+  nsresult Dispatch(already_AddRefed<HelperThreadTaskHandler> aRunnable);
+  void Shutdown();
+  HelperThreadPool();
+  virtual ~HelperThreadPool() = default;
+
+ private:
+  RefPtr<nsIThreadPool> mPool;
+};
+
+}  // namespace mozilla
+
+#endif