Bug 1288618 - Part 6: Avoid unnecessarily allocating a TailDispatcher for XPCOMThreadWrapper. r=bholley
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 21 Sep 2016 21:24:43 +1200
changeset 314810 637bc458366bd4c4968254ea7b18e3889731d5a5
parent 314809 252f4945c1071e530a129bb0cd10dfdf1d9bdf3a
child 314811 26730dd9f8c9952963693dbd65bdeb705d3ca635
push id30735
push usercbook@mozilla.com
push dateThu, 22 Sep 2016 09:55:35 +0000
treeherdermozilla-central@f0e6cc636021 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1288618
milestone52.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 1288618 - Part 6: Avoid unnecessarily allocating a TailDispatcher for XPCOMThreadWrapper. r=bholley
xpcom/threads/AbstractThread.cpp
xpcom/threads/AbstractThread.h
xpcom/threads/TaskQueue.cpp
--- a/xpcom/threads/AbstractThread.cpp
+++ b/xpcom/threads/AbstractThread.cpp
@@ -89,23 +89,45 @@ public:
 
       nsCOMPtr<nsIRunnable> event = NewRunnableMethod(this, &XPCOMThreadWrapper::FireTailDispatcher);
       nsContentUtils::RunInStableState(event.forget());
     }
 
     return mTailDispatcher.ref();
   }
 
+  virtual bool MightHaveTailTasks() override
+  {
+    return mTailDispatcher.isSome();
+  }
+
   virtual nsIThread* AsXPCOMThread() override { return mTarget; }
 
 private:
   RefPtr<nsIThread> mTarget;
   Maybe<AutoTaskDispatcher> mTailDispatcher;
 };
 
+void
+AbstractThread::TailDispatchTasksFor(AbstractThread* aThread)
+{
+  if (MightHaveTailTasks()) {
+    TailDispatcher().DispatchTasksFor(aThread);
+  }
+}
+
+bool
+AbstractThread::HasTailTasksFor(AbstractThread* aThread)
+{
+  if (!MightHaveTailTasks()) {
+    return false;
+  }
+  return TailDispatcher().HasTasksFor(aThread);
+}
+
 bool
 AbstractThread::RequiresTailDispatch(AbstractThread* aThread) const
 {
   MOZ_ASSERT(aThread);
   // We require tail dispatch if both the source and destination
   // threads support it.
   return SupportsTailDispatch() && aThread->SupportsTailDispatch();
 }
--- a/xpcom/threads/AbstractThread.h
+++ b/xpcom/threads/AbstractThread.h
@@ -61,16 +61,26 @@ public:
 
   // Returns a TaskDispatcher that will dispatch its tasks when the currently-
   // running tasks pops off the stack.
   //
   // May only be called when running within the it is invoked up, and only on
   // threads which support it.
   virtual TaskDispatcher& TailDispatcher() = 0;
 
+  // Returns true if we have tail tasks scheduled, or if this isn't known.
+  // Returns false if we definitely don't have any tail tasks.
+  virtual bool MightHaveTailTasks() { return true; }
+
+  // Helper functions for methods on the tail TasklDispatcher. These check
+  // HasTailTasks to avoid allocating a TailDispatcher if it isn't
+  // needed.
+  void TailDispatchTasksFor(AbstractThread* aThread);
+  bool HasTailTasksFor(AbstractThread* aThread);
+
   // Returns true if this supports the tail dispatcher.
   bool SupportsTailDispatch() const { return mSupportsTailDispatch; }
 
   // Returns true if this thread requires all dispatches originating from
   // aThread go through the tail dispatcher.
   bool RequiresTailDispatch(AbstractThread* aThread) const;
   bool RequiresTailDispatchFromCurrentThread() const;
 
--- a/xpcom/threads/TaskQueue.cpp
+++ b/xpcom/threads/TaskQueue.cpp
@@ -133,48 +133,48 @@ TaskQueue::AwaitIdle()
 }
 
 void
 TaskQueue::AwaitIdleLocked()
 {
   // Make sure there are no tasks for this queue waiting in the caller's tail
   // dispatcher.
   MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
-                !AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
+                !AbstractThread::GetCurrent()->HasTailTasksFor(this));
 
   mQueueMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(mIsRunning || mTasks.empty());
   while (mIsRunning) {
     mQueueMonitor.Wait();
   }
 }
 
 void
 TaskQueue::AwaitShutdownAndIdle()
 {
   MOZ_ASSERT(!IsCurrentThreadIn());
   // Make sure there are no tasks for this queue waiting in the caller's tail
   // dispatcher.
   MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
-                !AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
+                !AbstractThread::GetCurrent()->HasTailTasksFor(this));
 
   MonitorAutoLock mon(mQueueMonitor);
   while (!mIsShutdown) {
     mQueueMonitor.Wait();
   }
   AwaitIdleLocked();
 }
 
 RefPtr<ShutdownPromise>
 TaskQueue::BeginShutdown()
 {
   // Dispatch any tasks for this queue waiting in the caller's tail dispatcher,
   // since this is the last opportunity to do so.
   if (AbstractThread* currentThread = AbstractThread::GetCurrent()) {
-    currentThread->TailDispatcher().DispatchTasksFor(this);
+    currentThread->TailDispatchTasksFor(this);
   }
 
   MonitorAutoLock mon(mQueueMonitor);
   mIsShutdown = true;
   RefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
   MaybeResolveShutdown();
   mon.NotifyAll();
   return p;