Bug 1303077 - Annotate hangs that occur on the content process main thread during paint forcing. r?aklotz,billm draft
authorMike Conley <mconley@mozilla.com>
Thu, 13 Oct 2016 16:41:28 -0400
changeset 424945 fbf7224c145f2667981439924cde73926eb3d970
parent 423856 cce3483a31e91ca70627a3a1fc106aa737f7d5d4
child 424956 9b7ca80606cbc4f7d19f122680b75c6ce3fedb6c
push id32298
push usermconley@mozilla.com
push dateThu, 13 Oct 2016 20:46:27 +0000
reviewersaklotz, billm
bugs1303077
milestone52.0a1
Bug 1303077 - Annotate hangs that occur on the content process main thread during paint forcing. r?aklotz,billm MozReview-Commit-ID: 9UBsoy5sIJE
dom/ipc/ProcessHangMonitor.cpp
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -11,16 +11,17 @@
 #include "js/GCAPI.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/HangAnnotations.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 
 #include "nsIFrameLoader.h"
 #include "nsIHangReport.h"
 #include "nsITabParent.h"
@@ -67,16 +68,17 @@ using namespace mozilla::dom;
  */
 
 namespace {
 
 /* Child process objects */
 
 class HangMonitorChild
   : public PProcessHangMonitorChild
+  , public mozilla::HangMonitor::Annotator
 {
  public:
   explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
   virtual ~HangMonitorChild();
 
   void Open(Transport* aTransport, ProcessId aOtherPid,
             MessageLoop* aIOLoop);
 
@@ -109,29 +111,33 @@ class HangMonitorChild
 
   static HangMonitorChild* Get() { return sInstance; }
 
   MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
 
  private:
   void ShutdownOnThread();
 
+  virtual void
+  AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
+
   static Atomic<HangMonitorChild*> sInstance;
 
   const RefPtr<ProcessHangMonitor> mHangMonitor;
   Monitor mMonitor;
 
   // Main thread-only.
   bool mSentReport;
 
   // These fields must be accessed with mMonitor held.
   bool mTerminateScript;
   bool mStartDebugger;
   bool mFinishedStartingDebugger;
-  bool mForcePaint;
+  bool mForcePaintRequested;
+  bool mForcePaintInProgress;
   TabId mForcePaintTab;
   MOZ_INIT_OUTSIDE_CTOR uint64_t mForcePaintEpoch;
   JSContext* mContext;
   bool mShutdownDone;
 
   // This field is only accessed on the hang thread.
   bool mIPCOpen;
 };
@@ -266,17 +272,18 @@ private:
 
 HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
  : mHangMonitor(aMonitor),
    mMonitor("HangMonitorChild lock"),
    mSentReport(false),
    mTerminateScript(false),
    mStartDebugger(false),
    mFinishedStartingDebugger(false),
-   mForcePaint(false),
+   mForcePaintRequested(false),
+   mForcePaintInProgress(false),
    mShutdownDone(false),
    mIPCOpen(true)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   mContext = danger::GetJSContext();
 }
 
 HangMonitorChild::~HangMonitorChild()
@@ -286,60 +293,77 @@ HangMonitorChild::~HangMonitorChild()
   sInstance = nullptr;
 }
 
 void
 HangMonitorChild::InterruptCallback()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
-  bool forcePaint;
+  bool forcePaintRequested;
   TabId forcePaintTab;
   uint64_t forcePaintEpoch;
 
   {
     MonitorAutoLock lock(mMonitor);
-    forcePaint = mForcePaint;
+    forcePaintRequested = mForcePaintRequested;
     forcePaintTab = mForcePaintTab;
     forcePaintEpoch = mForcePaintEpoch;
 
-    mForcePaint = false;
+    mForcePaintRequested = false;
   }
 
-  if (forcePaint) {
+  if (forcePaintRequested) {
     RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
     if (tabChild) {
       JS::AutoAssertOnGC nogc(mContext);
       JS::AutoAssertOnBarrier nobarrier(mContext);
       tabChild->ForcePaint(forcePaintEpoch);
     }
+
+    MonitorAutoLock lock(mMonitor);
+    mForcePaintInProgress = false;
   }
 }
 
 void
 HangMonitorChild::Shutdown()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
+  mozilla::HangMonitor::UnregisterAnnotator(*this);
+
   MonitorAutoLock lock(mMonitor);
   while (!mShutdownDone) {
     mMonitor.Wait();
   }
 }
 
 void
 HangMonitorChild::ShutdownOnThread()
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   MonitorAutoLock lock(mMonitor);
   mShutdownDone = true;
   mMonitor.Notify();
 }
 
+/**
+ * This function is always called by the HangMonitor thread.
+ */
+void
+HangMonitorChild::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
+{
+  MonitorAutoLock lock(mMonitor);
+  if (mForcePaintInProgress) {
+    aAnnotations.AddAnnotation(NS_LITERAL_STRING("ForcePaintInProgress"), true);
+  }
+}
+
 void
 HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   mIPCOpen = false;
 
   // We use a task here to ensure that IPDL is finished with this
@@ -379,17 +403,18 @@ HangMonitorChild::RecvEndStartingDebugge
 
 bool
 HangMonitorChild::RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch)
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   {
     MonitorAutoLock lock(mMonitor);
-    mForcePaint = true;
+    mForcePaintRequested = true;
+    mForcePaintInProgress = true;
     mForcePaintTab = aTabId;
     mForcePaintEpoch = aLayerObserverEpoch;
   }
 
   JS_RequestInterruptCallback(mContext);
   JS::RequestGCInterruptCallback(mContext);
 
   return true;
@@ -1189,16 +1214,18 @@ mozilla::CreateHangMonitorChild(mozilla:
 
   JSContext* cx = danger::GetJSContext();
   JS_AddInterruptCallback(cx, InterruptCallback);
   JS::AddGCInterruptCallback(cx, InterruptCallback);
 
   ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate();
   HangMonitorChild* child = new HangMonitorChild(monitor);
 
+  mozilla::HangMonitor::RegisterAnnotator(*child);
+
   monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod
                                    <mozilla::ipc::Transport*,
                                     base::ProcessId,
                                     MessageLoop*>(child,
                                                   &HangMonitorChild::Open,
                                                   aTransport, aOtherPid,
                                                   XRE_GetIOMessageLoop()));