Add extra logging for comparing full/partial display list build times
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 20 Sep 2017 19:10:09 +0200
changeset 685665 c788cbd7e0d7c01dc3a3336606122997bf3f2a54
parent 685664 648083cbbe77806f615802643bdf60481428799e
child 685666 cd3cb07f54390a08ec4ee82db956c161a53d8841
push id86010
push userbmo:ethlin@mozilla.com
push dateWed, 25 Oct 2017 00:44:42 +0000
milestone58.0a1
Add extra logging for comparing full/partial display list build times
layout/base/nsLayoutUtils.cpp
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/RetainedDisplayListBuilder.h
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3794,17 +3794,20 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
   nsRect dirtyRect = visibleRegion.GetBounds();
 
   {
     AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame:BuildDisplayList",
                         GRAPHICS);
     AutoProfilerTracing tracing("Paint", "DisplayList");
 
     PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
-    TimeStamp dlStart = TimeStamp::Now();
+
+    TimeStamp dlTotalStart = TimeStamp::Now();
+    double retainedBuildTime = 0.0, fullBuildTime = 0.0;
+    DisplayListStatistics stats;
 
     {
       // If a scrollable container layer is created in nsDisplayList::PaintForFrame,
       // it will be the scroll parent for display items that are built in the
       // BuildDisplayListForStackingContext call below. We need to set the scroll
       // parent on the display list builder while we build those items, so that they
       // can pick up their scroll parent's id.
       ViewID id = FrameMetrics::NULL_SCROLL_ID;
@@ -3826,64 +3829,75 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
         }
       }
 
       nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
 
       builder.SetVisibleRect(dirtyRect);
       builder.SetIsBuilding(true);
 
+      TimeStamp dlStart = TimeStamp::Now();
+
       const bool paintedPreviously =
         aFrame->HasProperty(nsIFrame::ModifiedFrameList());
 
       bool merged = false;
       if (retainedBuilder && paintedPreviously) {
-        merged = retainedBuilder->AttemptPartialUpdate(aBackstop);
+        merged = retainedBuilder->AttemptPartialUpdate(aBackstop, stats);
+        stats.triedPartial = true;
+        stats.merged = merged;
       }
+      retainedBuildTime = (TimeStamp::Now() - dlStart).ToMilliseconds();
 
       if (merged && gfxPrefs::LayoutDisplayListBuildTwice()) {
         merged = false;
-        if (gfxPrefs::LayersDrawFPS()) {
-          if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
-            if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
-              pt->dl2Ms() = (TimeStamp::Now() - dlStart).ToMilliseconds();
-            }
-          }
-        }
         dlStart = TimeStamp::Now();
       }
 
       if (!merged) {
         list.DeleteAll(&builder);
         builder.EnterPresShell(aFrame);
         builder.SetDirtyRect(dirtyRect);
         builder.ClearWindowDraggingRegion();
         aFrame->BuildDisplayListForStackingContext(&builder, &list);
         AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
   
         builder.LeavePresShell(aFrame, &list);
       }
+      fullBuildTime = (TimeStamp::Now() - dlStart).ToMilliseconds();
     }
 
     builder.SetIsBuilding(false);
 
     // if (XRE_IsContentProcess()) {
     //   printf_stderr("Painting --- Full list:\n");
     //   nsFrame::PrintDisplayList(&builder, list);
     // }
 
     builder.IncrementPresShellPaintCount(presShell);
 
     if (gfxPrefs::LayersDrawFPS()) {
-      if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
-        if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
-          pt->dlMs() = (TimeStamp::Now() - dlStart).ToMilliseconds();
-        }
+      RefPtr<LayerManager> lm = builder.GetWidgetLayerManager();
+      PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm);
+
+      if (pt && gfxPrefs::LayoutDisplayListBuildTwice()) {
+        pt->dlMs() = retainedBuildTime;
+        pt->dl2Ms() = fullBuildTime;
+      } else if (pt) {
+        pt->dlMs() = (TimeStamp::Now() - dlTotalStart).ToMilliseconds();
       }
     }
+
+    if (stats.triedPartial && gfxPrefs::LayoutDisplayListBuildTwice()) {
+      printf(R"({ "retained": %.3f, "full": %.3f, "modifiedFrames": %d, )"
+             R"("listSize": %d, "hadCanvas": %d, "hadViewPort": %d, )"
+             R"("merged": %d },)" "\n",
+        retainedBuildTime, fullBuildTime, stats.modifiedFrames, list.Count(),
+        stats.hadCanvas, stats.hadViewport, stats.merged);
+    }
   }
 
   Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
                                  startBuildDisplayList);
 
   bool profilerNeedsDisplayList =
     profiler_feature_active(ProfilerFeature::DisplayListDump);
   bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint();
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -677,27 +677,45 @@ RetainedDisplayListBuilder::ComputeRebui
     }
   }
 
   return true;
 }
 
 
 bool
-RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop)
+RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop,
+                                                 DisplayListStatistics& aStats)
 {
   mBuilder.RemoveModifiedWindowDraggingRegion();
   if (mBuilder.ShouldSyncDecodeImages()) {
     MarkFramesWithItemsAndImagesModified(&mList);
   }
 
   mBuilder.EnterPresShell(mBuilder.RootReferenceFrame());
 
   std::vector<WeakFrame> modifiedFrames = GetModifiedFrames(mBuilder.RootReferenceFrame());
 
+  aStats.modifiedFrames = modifiedFrames.size();
+  for (WeakFrame& frame : modifiedFrames) {
+    if (!frame) {
+      continue;
+    }
+
+    LayoutFrameType type = frame->Type();
+    if (type == LayoutFrameType::Viewport ||
+        type == LayoutFrameType::PageContent) {
+      aStats.hadViewport = true;
+    }
+
+    if (type == LayoutFrameType::Canvas) {
+      aStats.hadCanvas = true;
+    }
+  }
+
   if (mPreviousCaret != mBuilder.GetCaretFrame()) {
     if (mPreviousCaret) {
       mBuilder.MarkFrameModifiedDuringBuilding(mPreviousCaret);
     }
 
     if (mBuilder.GetCaretFrame()) {
       mBuilder.MarkFrameModifiedDuringBuilding(mBuilder.GetCaretFrame());
     }
--- a/layout/painting/RetainedDisplayListBuilder.h
+++ b/layout/painting/RetainedDisplayListBuilder.h
@@ -2,32 +2,41 @@
  * 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 RETAINEDDISPLAYLISTBUILDER_H_
 #define RETAINEDDISPLAYLISTBUILDER_H_
 
 #include "nsDisplayList.h"
 
+struct DisplayListStatistics {
+  uint32_t modifiedFrames = 0;
+  bool triedPartial = false;
+  bool merged = false;
+
+  bool hadCanvas = false;
+  bool hadViewport = false;
+};
+
 struct RetainedDisplayListBuilder {
   RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
                              nsDisplayListBuilderMode aMode,
                              bool aBuildCaret)
     : mBuilder(aReferenceFrame, aMode, aBuildCaret, true)
   {}
   ~RetainedDisplayListBuilder()
   {
     mList.DeleteAll(&mBuilder);
   }
 
   nsDisplayListBuilder* Builder() { return &mBuilder; }
 
   nsDisplayList* List() { return &mList; }
 
-  bool AttemptPartialUpdate(nscolor aBackstop);
+  bool AttemptPartialUpdate(nscolor aBackstop, DisplayListStatistics& aStats);
 
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
 
 private:
   void PreProcessDisplayList(nsDisplayList* aList, AnimatedGeometryRoot* aAGR);
 
   void MergeDisplayLists(nsDisplayList* aNewList,
                          nsDisplayList* aOldList,