Bug 1440221 - Track stale computed values and style structs held by undisplayed maps in memory report. r?emilio,njn draft
authorXidorn Quan <me@upsuper.org>
Thu, 22 Feb 2018 23:19:50 +1100
changeset 759606 fc18f707b256a100df3dc56e7afc8c35b48caf4c
parent 759605 857dab806cbe19e5dec8f254cda708a2c1f0916c
push id100396
push userxquan@mozilla.com
push dateSun, 25 Feb 2018 22:59:15 +0000
reviewersemilio, njn
bugs1440221
milestone60.0a1
Bug 1440221 - Track stale computed values and style structs held by undisplayed maps in memory report. r?emilio,njn MozReview-Commit-ID: 8eXowQvUjyi
dom/base/nsWindowMemoryReporter.cpp
dom/base/nsWindowSizes.h
layout/base/PresShell.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -426,16 +426,20 @@ CollectWindowReports(nsGlobalWindowInner
 
   REPORT_SIZE("/layout/computed-values/non-dom", mLayoutComputedValuesNonDom,
               "Memory used by ComputedValues objects not accessible from DOM "
               "elements.");
 
   REPORT_SIZE("/layout/computed-values/visited", mLayoutComputedValuesVisited,
               "Memory used by ComputedValues objects used for visited styles.");
 
+  REPORT_SIZE("/layout/computed-values/stale", mLayoutComputedValuesStale,
+              "Memory used by ComputedValues and style structs it holds that "
+              "is no longer used but still alive.");
+
   REPORT_SIZE("/property-tables", mPropertyTablesSize,
               "Memory used for the property tables within a window.");
 
   REPORT_SIZE("/bindings", mBindingsSize,
               "Memory used by bindings within a window.");
 
   REPORT_COUNT("/dom/event-targets", mDOMEventTargetsCount,
                "Number of non-node event targets in the event targets table "
--- a/dom/base/nsWindowSizes.h
+++ b/dom/base/nsWindowSizes.h
@@ -189,16 +189,17 @@ class nsWindowSizes
   macro(Style, mLayoutServoStyleSetsOther) \
   macro(Style, mLayoutServoElementDataObjects) \
   macro(Other, mLayoutTextRunsSize) \
   macro(Other, mLayoutPresContextSize) \
   macro(Other, mLayoutFramePropertiesSize) \
   macro(Style, mLayoutComputedValuesDom) \
   macro(Style, mLayoutComputedValuesNonDom) \
   macro(Style, mLayoutComputedValuesVisited) \
+  macro(Style, mLayoutComputedValuesStale) \
   macro(Other, mPropertyTablesSize) \
   macro(Other, mBindingsSize) \
 
 public:
   explicit nsWindowSizes(mozilla::SizeOfState& aState)
     :
       FOR_EACH_SIZE(ZERO_SIZE)
       mDOMEventTargetsCount(0),
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10653,20 +10653,17 @@ PresShell::AddSizeOfIncludingThis(nsWind
     StyleSet()->AsServo()->AddSizeOfIncludingThis(aSizes);
   }
 
   aSizes.mLayoutTextRunsSize += SizeOfTextRuns(mallocSizeOf);
 
   aSizes.mLayoutPresContextSize +=
     mPresContext->SizeOfIncludingThis(mallocSizeOf);
 
-  nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
-  if (rootFrame) {
-    rootFrame->AddSizeOfExcludingThisForTree(aSizes);
-  }
+  mFrameConstructor->AddSizeOfIncludingThis(aSizes);
 }
 
 size_t
 PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const
 {
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   if (!rootFrame) {
     return 0;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/HTMLDetailsElement.h"
 #include "mozilla/dom/HTMLSelectElement.h"
 #include "mozilla/dom/HTMLSummaryElement.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Likely.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/MemoryReporting.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ServoBindings.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsCSSPseudoElements.h"
 #include "nsAtom.h"
 #include "nsIFrameInlines.h"
 #include "nsGkAtoms.h"
 #include "nsPresContext.h"
@@ -13144,8 +13145,27 @@ nsCSSFrameConstructor::FreeFCItem(FrameC
     mFCItemPool.Clear();
   } else {
     // Prepend it to the list of free items.
     FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
     item->mNext = mFirstFreeFCItem;
     mFirstFreeFCItem = item;
   }
 }
+
+void
+nsCSSFrameConstructor::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
+{
+  if (nsIFrame* rootFrame = GetRootFrame()) {
+    rootFrame->AddSizeOfExcludingThisForTree(aSizes);
+  }
+
+  // This must be done after measuring from the frame tree, since frame
+  // manager will measure sizes of staled computed values and style
+  // structs, which only make sense after we know what are being used.
+  nsFrameManager::AddSizeOfIncludingThis(aSizes);
+
+  // Measurement of the following members may be added later if DMD finds it
+  // is worthwhile:
+  // - mFCItemPool
+  // - mQuoteList
+  // - mCounterManager
+}
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -388,16 +388,18 @@ public:
   // have a psuedo-element style
   nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
   nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
 
   // Get the frame that is the parent of the root element.
   nsContainerFrame* GetDocElementContainingBlock()
     { return mDocElementContainingBlock; }
 
+  void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
+
 private:
   struct FrameConstructionItem;
   class FrameConstructionItemList;
 
   nsContainerFrame* ConstructPageFrame(nsIPresShell*      aPresShell,
                                        nsContainerFrame*  aParentFrame,
                                        nsIFrame*          aPrevPageFrame,
                                        nsContainerFrame*& aCanvasFrame);
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -24,16 +24,18 @@
 #include "nsAbsoluteContainingBlock.h"
 #include "ChildIterator.h"
 
 #include "nsFrameManager.h"
 #include "GeckoProfiler.h"
 #include "nsIStatefulFrame.h"
 #include "nsContainerFrame.h"
 
+#include "mozilla/MemoryReporting.h"
+
 // #define DEBUG_UNDISPLAYED_MAP
 // #define DEBUG_DISPLAY_CONTENTS_MAP
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 
@@ -88,16 +90,18 @@ public:
    *
    * All functions that are entry points into code that handles "parent"
    * objects (used as the hash table keys) must ensure that the parent objects
    * that they act on (and pass to other code) have been normalized by calling
    * this method.
    */
   static nsIContent* GetApplicableParent(nsIContent* aParent);
 
+  void AddSizeOfIncludingThis(nsWindowSizes& aSizes, bool aIsServo) const;
+
 protected:
   LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
   LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
   void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
 };
 
 //----------------------------------------------------------------------
 
@@ -691,16 +695,29 @@ nsFrameManager::DestroyAnonymousContent(
     // teardown code to determine whether to invoke ClearAllMapsFor or not.
     // These maps will go away when we drop support for the old style system.
     ClearAllMapsFor(content);
 
     content->UnbindFromTree();
   }
 }
 
+void
+nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
+{
+  bool isServo = mPresShell->StyleSet()->IsServo();
+  aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
+  if (mDisplayNoneMap) {
+    mDisplayNoneMap->AddSizeOfIncludingThis(aSizes, isServo);
+  }
+  if (mDisplayContentsMap) {
+    mDisplayContentsMap->AddSizeOfIncludingThis(aSizes, isServo);
+  }
+}
+
 //----------------------------------------------------------------------
 
 nsFrameManagerBase::UndisplayedMap::UndisplayedMap()
 {
   MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
 }
 
 nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
@@ -825,8 +842,36 @@ nsFrameManagerBase::UndisplayedMap::Remo
 {
   nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
   if (list) {
     while (auto* node = list->popFirst()) {
       delete node;
     }
   }
 }
+
+void
+nsFrameManagerBase::UndisplayedMap::
+AddSizeOfIncludingThis(nsWindowSizes& aSizes, bool aIsServo) const
+{
+  MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
+  aSizes.mLayoutPresShellSize += ShallowSizeOfIncludingThis(mallocSizeOf);
+
+  nsWindowSizes staleSizes(aSizes.mState);
+  for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
+    const LinkedList<UndisplayedNode>* list = iter.UserData();
+    aSizes.mLayoutPresShellSize += list->sizeOfExcludingThis(mallocSizeOf);
+    if (!aIsServo) {
+      // Computed values and style structs can only be stale when using
+      // Servo style system.
+      continue;
+    }
+    for (const UndisplayedNode* node = list->getFirst();
+          node; node = node->getNext()) {
+      ServoStyleContext* sc = node->mStyle->AsServo();
+      if (!aSizes.mState.HaveSeenPtr(sc)) {
+        sc->AddSizeOfIncludingThis(
+          staleSizes, &aSizes.mLayoutComputedValuesStale);
+      }
+    }
+  }
+  aSizes.mLayoutComputedValuesStale += staleSizes.getTotalSize();
+}
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -12,16 +12,17 @@
 #include "nsFrameManagerBase.h"
 
 #include "nsFrameList.h"
 #include "nsIContent.h"
 #include "nsStyleContext.h"
 
 class nsContainerFrame;
 class nsPlaceholderFrame;
+class nsWindowSizes;
 
 namespace mozilla {
 /**
  * Node in a linked list, containing the style for an element that
  * does not have a frame but whose parent does have a frame.
  */
 struct UndisplayedNode : public LinkedListElement<UndisplayedNode>
 {
@@ -195,16 +196,18 @@ public:
    * Add/restore state for one frame
    */
   void CaptureFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
 
   void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
 
   void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
 
+  void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
+
 protected:
   static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent);
 
   void ClearAllMapsFor(nsIContent* aParentContent);
 
   static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
                                               const nsIContent* aContent);
   static mozilla::UndisplayedNode*