Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp

Issue 2711893002: Loosen FirstMeaningfulPaint UMA network-idle heuristics (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/paint/FirstMeaningfulPaintDetector.h" 5 #include "core/paint/FirstMeaningfulPaintDetector.h"
6 6
7 #include "core/css/FontFaceSet.h" 7 #include "core/css/FontFaceSet.h"
8 #include "core/dom/TaskRunnerHelper.h" 8 #include "core/dom/TaskRunnerHelper.h"
9 #include "core/paint/PaintTiming.h" 9 #include "core/paint/PaintTiming.h"
10 #include "platform/Histogram.h"
10 #include "platform/instrumentation/tracing/TraceEvent.h" 11 #include "platform/instrumentation/tracing/TraceEvent.h"
11 #include "platform/loader/fetch/ResourceFetcher.h" 12 #include "platform/loader/fetch/ResourceFetcher.h"
12 13
13 namespace blink { 14 namespace blink {
14 15
15 namespace { 16 namespace {
16 17
17 // Web fonts that laid out more than this number of characters block First 18 // Web fonts that laid out more than this number of characters block First
18 // Meaningful Paint. 19 // Meaningful Paint.
19 const int kBlankCharactersThreshold = 200; 20 const int kBlankCharactersThreshold = 200;
20 21
21 // FirstMeaningfulPaintDetector stops observing layouts and reports First 22 // The page is n-quiet if there are no more than n active network requests for
22 // Meaningful Paint when this duration passed from last network activity. 23 // this duration of time.
23 const double kSecondsWithoutNetworkActivityThreshold = 0.5; 24 const double kNetwork2QuietWindowSeconds = 3;
25 const double kNetwork0QuietWindowSeconds = 0.5;
24 26
25 } // namespace 27 } // namespace
26 28
27 FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::from( 29 FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::from(
28 Document& document) { 30 Document& document) {
29 return PaintTiming::from(document).firstMeaningfulPaintDetector(); 31 return PaintTiming::from(document).firstMeaningfulPaintDetector();
30 } 32 }
31 33
32 FirstMeaningfulPaintDetector::FirstMeaningfulPaintDetector( 34 FirstMeaningfulPaintDetector::FirstMeaningfulPaintDetector(
33 PaintTiming* paintTiming, 35 PaintTiming* paintTiming,
(...skipping 11 matching lines...) Expand all
45 // Computes "layout significance" (http://goo.gl/rytlPL) of a layout operation. 47 // Computes "layout significance" (http://goo.gl/rytlPL) of a layout operation.
46 // Significance of a layout is the number of layout objects newly added to the 48 // Significance of a layout is the number of layout objects newly added to the
47 // layout tree, weighted by page height (before and after the layout). 49 // layout tree, weighted by page height (before and after the layout).
48 // A paint after the most significance layout during page load is reported as 50 // A paint after the most significance layout during page load is reported as
49 // First Meaningful Paint. 51 // First Meaningful Paint.
50 void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded( 52 void FirstMeaningfulPaintDetector::markNextPaintAsMeaningfulIfNeeded(
51 const LayoutObjectCounter& counter, 53 const LayoutObjectCounter& counter,
52 int contentsHeightBeforeLayout, 54 int contentsHeightBeforeLayout,
53 int contentsHeightAfterLayout, 55 int contentsHeightAfterLayout,
54 int visibleHeight) { 56 int visibleHeight) {
55 if (m_state == Reported) 57 if (m_networkState == Network0Quiet)
56 return; 58 return;
57 59
58 unsigned delta = counter.count() - m_prevLayoutObjectCount; 60 unsigned delta = counter.count() - m_prevLayoutObjectCount;
59 m_prevLayoutObjectCount = counter.count(); 61 m_prevLayoutObjectCount = counter.count();
60 62
61 if (visibleHeight == 0) 63 if (visibleHeight == 0)
62 return; 64 return;
63 65
64 double ratioBefore = std::max( 66 double ratioBefore = std::max(
65 1.0, static_cast<double>(contentsHeightBeforeLayout) / visibleHeight); 67 1.0, static_cast<double>(contentsHeightBeforeLayout) / visibleHeight);
66 double ratioAfter = std::max( 68 double ratioAfter = std::max(
67 1.0, static_cast<double>(contentsHeightAfterLayout) / visibleHeight); 69 1.0, static_cast<double>(contentsHeightAfterLayout) / visibleHeight);
68 double significance = delta / ((ratioBefore + ratioAfter) / 2); 70 double significance = delta / ((ratioBefore + ratioAfter) / 2);
69 71
70 // If the page has many blank characters, the significance value is 72 // If the page has many blank characters, the significance value is
71 // accumulated until the text become visible. 73 // accumulated until the text become visible.
72 int approximateBlankCharacterCount = 74 int approximateBlankCharacterCount =
73 FontFaceSet::approximateBlankCharacterCount(*document()); 75 FontFaceSet::approximateBlankCharacterCount(*document());
74 if (approximateBlankCharacterCount > kBlankCharactersThreshold) { 76 if (approximateBlankCharacterCount > kBlankCharactersThreshold) {
75 m_accumulatedSignificanceWhileHavingBlankText += significance; 77 m_accumulatedSignificanceWhileHavingBlankText += significance;
76 } else { 78 } else {
77 significance += m_accumulatedSignificanceWhileHavingBlankText; 79 significance += m_accumulatedSignificanceWhileHavingBlankText;
78 m_accumulatedSignificanceWhileHavingBlankText = 0; 80 m_accumulatedSignificanceWhileHavingBlankText = 0;
79 if (significance > m_maxSignificanceSoFar) { 81 if (significance > m_maxSignificanceSoFar) {
80 m_state = NextPaintIsMeaningful; 82 m_nextPaintIsMeaningful = true;
81 m_maxSignificanceSoFar = significance; 83 m_maxSignificanceSoFar = significance;
82 } 84 }
83 } 85 }
84 } 86 }
85 87
86 void FirstMeaningfulPaintDetector::notifyPaint() { 88 void FirstMeaningfulPaintDetector::notifyPaint() {
87 if (m_state != NextPaintIsMeaningful) 89 if (!m_nextPaintIsMeaningful)
88 return; 90 return;
89 91
90 // Skip document background-only paints. 92 // Skip document background-only paints.
91 if (m_paintTiming->firstPaint() == 0.0) 93 if (m_paintTiming->firstPaint() == 0.0)
92 return; 94 return;
93 95
94 m_provisionalFirstMeaningfulPaint = monotonicallyIncreasingTime(); 96 m_provisionalFirstMeaningfulPaint = monotonicallyIncreasingTime();
95 m_state = NextPaintIsNotMeaningful; 97 m_nextPaintIsMeaningful = false;
98 m_networkStateAtFirstMeaningfulPaint = m_networkState;
99
100 if (m_networkState != NetworkActive)
101 return;
96 102
97 TRACE_EVENT_MARK_WITH_TIMESTAMP1( 103 TRACE_EVENT_MARK_WITH_TIMESTAMP1(
98 "loading", "firstMeaningfulPaintCandidate", 104 "loading", "firstMeaningfulPaintCandidate",
99 TraceEvent::toTraceTimestamp(m_provisionalFirstMeaningfulPaint), "frame", 105 TraceEvent::toTraceTimestamp(m_provisionalFirstMeaningfulPaint), "frame",
100 document()->frame()); 106 document()->frame());
101 // Ignore the first meaningful paint candidate as this generally is the first 107 // Ignore the first meaningful paint candidate as this generally is the first
102 // contentful paint itself. 108 // contentful paint itself.
103 if (!m_seenFirstMeaningfulPaintCandidate) { 109 if (!m_seenFirstMeaningfulPaintCandidate) {
104 m_seenFirstMeaningfulPaintCandidate = true; 110 m_seenFirstMeaningfulPaintCandidate = true;
105 return; 111 return;
106 } 112 }
107 m_paintTiming->markFirstMeaningfulPaintCandidate(); 113 m_paintTiming->markFirstMeaningfulPaintCandidate();
108 } 114 }
109 115
116 bool FirstMeaningfulPaintDetector::isNetworkQuiet(int maxActiveConnections) {
117 DCHECK(document());
118 if (!document()->hasFinishedParsing())
119 return false;
120 ResourceFetcher* fetcher = document()->fetcher();
121 return fetcher->blockingRequestCount() + fetcher->nonblockingRequestCount() <=
122 maxActiveConnections;
123 }
124
110 void FirstMeaningfulPaintDetector::checkNetworkStable() { 125 void FirstMeaningfulPaintDetector::checkNetworkStable() {
111 DCHECK(document()); 126 switch (m_networkState) {
112 if (m_state == Reported || document()->fetcher()->hasPendingRequest()) 127 case NetworkActive:
113 return; 128 if (!isNetworkQuiet(2))
129 return;
130 m_networkStableTimer.startOneShot(kNetwork2QuietWindowSeconds,
131 BLINK_FROM_HERE);
132 break;
114 133
115 m_networkStableTimer.startOneShot(kSecondsWithoutNetworkActivityThreshold, 134 case Network2Quiet:
116 BLINK_FROM_HERE); 135 if (!isNetworkQuiet(0))
136 return;
137 m_networkStableTimer.startOneShot(kNetwork0QuietWindowSeconds,
138 BLINK_FROM_HERE);
139 break;
140
141 case Network0Quiet:
142 break;
143 }
117 } 144 }
118 145
119 void FirstMeaningfulPaintDetector::networkStableTimerFired(TimerBase*) { 146 void FirstMeaningfulPaintDetector::networkStableTimerFired(TimerBase*) {
120 if (m_state == Reported || !document() || 147 // This histogram is logged when the page reached network 0-quiet, so only
121 document()->fetcher()->hasPendingRequest() || 148 // possible values are NetworkActive and Network2Quiet.
122 !m_paintTiming->firstContentfulPaint()) 149 DEFINE_STATIC_LOCAL(
150 EnumerationHistogram, networkStateAtFirstMeaningfulPaintHistogram,
151 ("PageLoad.Experimental.PaintTiming.NetworkStateAtFirstMeaningfulPaint",
152 Network0Quiet));
153
154 if (!document())
123 return; 155 return;
124 156
125 if (m_provisionalFirstMeaningfulPaint) { 157 switch (m_networkState) {
126 // Enforce FirstContentfulPaint <= FirstMeaningfulPaint. 158 case NetworkActive:
127 double timestamp = std::max(m_provisionalFirstMeaningfulPaint, 159 if (!isNetworkQuiet(2) || !m_paintTiming->firstContentfulPaint())
128 m_paintTiming->firstContentfulPaint()); 160 return;
129 m_paintTiming->setFirstMeaningfulPaint(timestamp); 161 m_networkState = Network2Quiet;
162 // Report FirstMeaningfulPaint when the page reached network 2-quiet.
163 if (m_provisionalFirstMeaningfulPaint) {
164 // Enforce FirstContentfulPaint <= FirstMeaningfulPaint.
165 double timestamp = std::max(m_provisionalFirstMeaningfulPaint,
166 m_paintTiming->firstContentfulPaint());
167 m_paintTiming->setFirstMeaningfulPaint(timestamp);
168 }
169 checkNetworkStable();
170 break;
171
172 case Network2Quiet:
173 if (!isNetworkQuiet(0))
174 return;
175 m_networkState = Network0Quiet;
176 networkStateAtFirstMeaningfulPaintHistogram.count(
177 m_networkStateAtFirstMeaningfulPaint);
178 break;
179
180 case Network0Quiet:
181 NOTREACHED();
182 break;
130 } 183 }
131 m_state = Reported;
132 } 184 }
133 185
134 DEFINE_TRACE(FirstMeaningfulPaintDetector) { 186 DEFINE_TRACE(FirstMeaningfulPaintDetector) {
135 visitor->trace(m_paintTiming); 187 visitor->trace(m_paintTiming);
136 } 188 }
137 189
138 } // namespace blink 190 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698