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: tracing/tracing/metrics/system_health/first_paint_metric.html

Issue 2083213002: Change call-sites in trace viewer to use generators instead of iteration functions. (Closed) Base URL: git@github.com:catapult-project/catapult@master
Patch Set: fix break/continue Created 4 years, 5 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 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <!-- 2 <!--
3 Copyright 2016 The Chromium Authors. All rights reserved. 3 Copyright 2016 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be 4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file. 5 found in the LICENSE file.
6 --> 6 -->
7 7
8 <link rel="import" href="/tracing/base/statistics.html"> 8 <link rel="import" href="/tracing/base/statistics.html">
9 <link rel="import" href="/tracing/metrics/metric_registry.html"> 9 <link rel="import" href="/tracing/metrics/metric_registry.html">
10 <link rel="import" href="/tracing/metrics/system_health/utils.html"> 10 <link rel="import" href="/tracing/metrics/system_health/utils.html">
(...skipping 25 matching lines...) Expand all
36 return chromeHelper.rendererHelpers[largestPid]; 36 return chromeHelper.rendererHelpers[largestPid];
37 } 37 }
38 38
39 /** 39 /**
40 * A utility class for finding navigationStart event for given frame and 40 * A utility class for finding navigationStart event for given frame and
41 * timestamp. 41 * timestamp.
42 * @constructor 42 * @constructor
43 */ 43 */
44 function NavigationStartFinder(rendererHelper) { 44 function NavigationStartFinder(rendererHelper) {
45 this.navigationStartsForFrameId_ = {}; 45 this.navigationStartsForFrameId_ = {};
46 rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer( 46 for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
47 () => true, function(ev) { 47 if (ev.category === 'blink.user_timing' &&
charliea (OOO until 10-5) 2016/06/29 18:08:44 high level nit: big refactorings like this one are
charliea (OOO until 10-5) 2016/06/29 18:08:44 nit: I think the old way of writing this was more
alexandermont 2016/06/29 20:47:11 Done
48 if (ev.category !== 'blink.user_timing' || 48 ev.title === 'navigationStart') {
49 ev.title !== 'navigationStart') 49 var frameIdRef = ev.args['frame'];
50 return; 50 var list = this.navigationStartsForFrameId_[frameIdRef];
51 51 if (list === undefined) {
52 var frameIdRef = ev.args['frame']; 52 this.navigationStartsForFrameId_[frameIdRef] = list = [];
53 var list = this.navigationStartsForFrameId_[frameIdRef]; 53 }
54 if (list === undefined) { 54 list.unshift(ev);
charliea (OOO until 10-5) 2016/06/29 18:08:44 nit: bad indentation
alexandermont 2016/06/29 20:47:11 Done
55 this.navigationStartsForFrameId_[frameIdRef] = list = []; 55 }
56 } 56 }
57 list.unshift(ev);
58 },
59 this);
60 } 57 }
61 58
62 NavigationStartFinder.prototype = { 59 NavigationStartFinder.prototype = {
63 findNavigationStartEventForFrameBeforeTimestamp: function(frameIdRef, ts) { 60 findNavigationStartEventForFrameBeforeTimestamp: function(frameIdRef, ts) {
64 var list = this.navigationStartsForFrameId_[frameIdRef]; 61 var list = this.navigationStartsForFrameId_[frameIdRef];
65 if (list === undefined) { 62 if (list === undefined) {
66 console.warn('No navigationStartEvent found for frame id "' + 63 console.warn('No navigationStartEvent found for frame id "' +
67 frameIdRef + '"'); 64 frameIdRef + '"');
68 return undefined; 65 return undefined;
69 } 66 }
67 for (var ev of list)
charliea (OOO until 10-5) 2016/06/29 18:08:44 same note (here and below): in this CL, please do
alexandermont 2016/06/29 20:47:11 Done
68 if (ev.start <= ts)
69 return ev;
70 70
71 var eventBeforeTimestamp; 71 console.warn('Failed to find navigationStartEvent.');
72 list.forEach(function(ev) { 72 return undefined;
73 if (ev.start > ts)
74 return;
75
76 if (eventBeforeTimestamp === undefined)
77 eventBeforeTimestamp = ev;
78 }, this);
79 if (eventBeforeTimestamp === undefined) {
80 console.warn('Failed to find navigationStartEvent.');
81 return undefined;
82 }
83 return eventBeforeTimestamp;
84 } 73 }
85 }; 74 };
86 75
87 /** 76 /**
88 * A utility class for finding Paint event for given frame and timestamp. 77 * A utility class for finding Paint event for given frame and timestamp.
89 * @constructor 78 * @constructor
90 */ 79 */
91 function PaintFinder(rendererHelper) { 80 function PaintFinder(rendererHelper) {
92 this.paintsForFrameId_ = {}; 81 this.paintsForFrameId_ = {};
93 rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer( 82 for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
94 () => true, function(ev) { 83 if (ev.category === 'devtools.timeline' && ev.title === 'Paint') {
95 if (ev.category !== 'devtools.timeline' || ev.title !== 'Paint') 84 var frameIdRef = ev.args['data']['frame'];
96 return; 85 var list = this.paintsForFrameId_[frameIdRef];
97 86 if (list === undefined)
98 var frameIdRef = ev.args['data']['frame']; 87 this.paintsForFrameId_[frameIdRef] = list = [];
99 var list = this.paintsForFrameId_[frameIdRef]; 88 list.push(ev);
100 if (list === undefined) 89 }
101 this.paintsForFrameId_[frameIdRef] = list = []; 90 }
102 list.push(ev);
103 },
104 this);
105 } 91 }
106 92
107 PaintFinder.prototype = { 93 PaintFinder.prototype = {
108 findPaintEventForFrameAfterTimestamp: function(frameIdRef, ts) { 94 findPaintEventForFrameAfterTimestamp: function(frameIdRef, ts) {
109 var list = this.paintsForFrameId_[frameIdRef]; 95 var list = this.paintsForFrameId_[frameIdRef];
110 if (list === undefined) 96 if (list === undefined)
111 return undefined; 97 return undefined;
112 98
113 var eventAfterTimestamp; 99 for (var ev of list)
114 list.forEach(function(ev) { 100 if (ev.start >= ts)
115 if (ev.start < ts) 101 return ev;
116 return; 102 return undefined;
117
118 if (eventAfterTimestamp === undefined)
119 eventAfterTimestamp = ev;
120 }, this);
121 return eventAfterTimestamp;
122 } 103 }
123 }; 104 };
124 105
125 var FIRST_PAINT_NUMERIC_BUILDER = 106 var FIRST_PAINT_NUMERIC_BUILDER =
126 new tr.v.NumericBuilder(timeDurationInMs_smallerIsBetter, 0) 107 new tr.v.NumericBuilder(timeDurationInMs_smallerIsBetter, 0)
127 .addLinearBins(1000, 20) // 50ms step to 1s 108 .addLinearBins(1000, 20) // 50ms step to 1s
128 .addLinearBins(3000, 20) // 100ms step to 3s 109 .addLinearBins(3000, 20) // 100ms step to 3s
129 .addExponentialBins(20000, 20); 110 .addExponentialBins(20000, 20);
130 function createHistogram() { 111 function createHistogram() {
131 var histogram = FIRST_PAINT_NUMERIC_BUILDER.build(); 112 var histogram = FIRST_PAINT_NUMERIC_BUILDER.build();
(...skipping 13 matching lines...) Expand all
145 var snapshot; 126 var snapshot;
146 127
147 var objects = rendererHelper.process.objects; 128 var objects = rendererHelper.process.objects;
148 var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader']; 129 var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader'];
149 if (frameLoaderInstances === undefined) { 130 if (frameLoaderInstances === undefined) {
150 console.warn('Failed to find FrameLoader for frameId "' + frameIdRef + 131 console.warn('Failed to find FrameLoader for frameId "' + frameIdRef +
151 '" at ts ' + ts + ', the trace maybe incomplete or from an old' + 132 '" at ts ' + ts + ', the trace maybe incomplete or from an old' +
152 'Chrome.'); 133 'Chrome.');
153 return undefined; 134 return undefined;
154 } 135 }
155 frameLoaderInstances.forEach(function(instance) { 136 for (var instance of frameLoaderInstances) {
156 if (!instance.isAliveAt(ts)) 137 if (!instance.isAliveAt(ts))
157 return; 138 continue;
158 var maybeSnapshot = instance.getSnapshotAt(ts); 139 var snapshot = instance.getSnapshotAt(ts);
159 if (frameIdRef !== maybeSnapshot.args['frame']['id_ref']) 140 if (frameIdRef === snapshot.args['frame']['id_ref'])
160 return; 141 return snapshot;
161 142 }
162 snapshot = maybeSnapshot;
163 }, this);
164
165 return snapshot;
166 } 143 }
167 144
168 function findAllUserTimingEvents(rendererHelper, title) { 145 function findAllUserTimingEvents(rendererHelper, title) {
169 var targetEvents = []; 146 var targetEvents = [];
170 147
171 rendererHelper.process.iterateAllEvents( 148 for (var ev of rendererHelper.process.descendantEvents())
172 function(ev) { 149 if (ev.category === 'blink.user_timing' && ev.title === title)
173 if (ev.category !== 'blink.user_timing' || 150 targetEvents.push(ev);
174 ev.title !== title)
175 return;
176
177 targetEvents.push(ev);
178 }, this);
179 151
180 return targetEvents; 152 return targetEvents;
181 } 153 }
182 154
183 function findAllLayoutEvents(rendererHelper) { 155 function findAllLayoutEvents(rendererHelper) {
184 var isTelemetryInternalEvent = 156 var isTelemetryInternalEvent =
185 prepareTelemetryInternalEventPredicate(rendererHelper); 157 prepareTelemetryInternalEventPredicate(rendererHelper);
186 var layoutsForFrameId = {}; 158 var layoutsForFrameId = {};
187 rendererHelper.process.iterateAllEvents( 159 for (var ev of rendererHelper.process.descendantEvents()) {
188 function(ev) { 160 if (ev.category !==
189 if (ev.category !== 161 'blink,benchmark,disabled-by-default-blink.debug.layout' ||
190 'blink,benchmark,disabled-by-default-blink.debug.layout' || 162 ev.title !== 'FrameView::performLayout')
191 ev.title !== 'FrameView::performLayout') 163 continue;
192 return; 164 if (isTelemetryInternalEvent(ev))
193 if (isTelemetryInternalEvent(ev)) 165 continue;
194 return; 166 if (ev.args.counters === undefined) {
195 if (ev.args.counters === undefined) { 167 console.warn('Ignoring FrameView::performLayout event with no ' +
196 console.warn('Ignoring FrameView::performLayout event with no ' + 168 'counters arg (END event is missing).');
197 'counters arg (END event is missing).'); 169 continue;
198 return; 170 }
199 } 171 var frameIdRef = ev.args.counters['frame'];
200 var frameIdRef = ev.args.counters['frame']; 172 if (frameIdRef === undefined)
201 if (frameIdRef === undefined) 173 continue;
202 return; 174 var list = layoutsForFrameId[frameIdRef];
203 var list = layoutsForFrameId[frameIdRef]; 175 if (list === undefined)
204 if (list === undefined) 176 layoutsForFrameId[frameIdRef] = list = [];
205 layoutsForFrameId[frameIdRef] = list = []; 177 list.push(ev);
206 list.push(ev); 178 }
207 }, this);
208 return layoutsForFrameId; 179 return layoutsForFrameId;
209 } 180 }
210 181
211 function prepareTelemetryInternalEventPredicate(rendererHelper) { 182 function prepareTelemetryInternalEventPredicate(rendererHelper) {
212 var ignoreRegions = []; 183 var ignoreRegions = [];
213 184
214 var internalRegionStart; 185 var internalRegionStart;
215 rendererHelper.mainThread.asyncSliceGroup.iterateAllEventsInThisContainer( 186 for (var slice of
216 () => true, function(slice) { 187 rendererHelper.mainThread.asyncSliceGroup.descendantEvents()) {
217 if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.start$/)) 188 if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.start$/))
218 internalRegionStart = slice.start; 189 internalRegionStart = slice.start;
219 if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.end$/)) { 190 if (!!slice.title.match(/^telemetry\.internal\.[^.]*\.end$/)) {
220 var timedEvent = new tr.model.TimedEvent(internalRegionStart); 191 var timedEvent = new tr.model.TimedEvent(internalRegionStart);
221 timedEvent.duration = slice.end - internalRegionStart; 192 timedEvent.duration = slice.end - internalRegionStart;
222 ignoreRegions.push(timedEvent); 193 ignoreRegions.push(timedEvent);
223 } 194 }
224 }, this); 195 }
225 196
226 return function isTelemetryInternalEvent(slice) { 197 return function isTelemetryInternalEvent(slice) {
227 for (var i = 0; i < ignoreRegions.length; ++ i) { 198 for (var region of ignoreRegions)
228 if (ignoreRegions[i].bounds(slice)) 199 if (region.bounds(slice))
229 return true; 200 return true;
230 }
231 return false; 201 return false;
232 } 202 }
233 } 203 }
234 204
235 var URL_BLACKLIST = [ 205 var URL_BLACKLIST = [
236 'about:blank', 206 'about:blank',
237 // Chrome on Android creates main frames with the below URL for plugins. 207 // Chrome on Android creates main frames with the below URL for plugins.
238 'data:text/html,pluginplaceholderdata' 208 'data:text/html,pluginplaceholderdata'
239 ]; 209 ];
240 function shouldIgnoreURL(url) { 210 function shouldIgnoreURL(url) {
(...skipping 14 matching lines...) Expand all
255 }]; 225 }];
256 226
257 function firstContentfulPaintMetric(values, model) { 227 function firstContentfulPaintMetric(values, model) {
258 var chromeHelper = model.getOrCreateHelper( 228 var chromeHelper = model.getOrCreateHelper(
259 tr.model.helpers.ChromeModelHelper); 229 tr.model.helpers.ChromeModelHelper);
260 var rendererHelper = findTargetRendererHelper(chromeHelper); 230 var rendererHelper = findTargetRendererHelper(chromeHelper);
261 var isTelemetryInternalEvent = 231 var isTelemetryInternalEvent =
262 prepareTelemetryInternalEventPredicate(rendererHelper); 232 prepareTelemetryInternalEventPredicate(rendererHelper);
263 var navigationStartFinder = new NavigationStartFinder(rendererHelper); 233 var navigationStartFinder = new NavigationStartFinder(rendererHelper);
264 234
265 METRICS.forEach(function(metric) { 235 for (var metric of METRICS) {
266 var histogram = createHistogram(); 236 var histogram = createHistogram();
267 var targetEvents = findAllUserTimingEvents(rendererHelper, metric.title); 237 var targetEvents = findAllUserTimingEvents(rendererHelper, metric.title);
268 targetEvents = targetEvents.filter( 238 for (var ev of targetEvents) {
269 (ev) => !isTelemetryInternalEvent(ev)); 239 if (isTelemetryInternalEvent(ev))
270 targetEvents.forEach(function(ev) { 240 continue;
271 var frameIdRef = ev.args['frame']; 241 var frameIdRef = ev.args['frame'];
272 var snapshot = 242 var snapshot =
273 findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ev.start); 243 findFrameLoaderSnapshotAt(rendererHelper, frameIdRef, ev.start);
274 if (snapshot === undefined || !snapshot.args.isLoadingMainFrame) 244 if (snapshot === undefined || !snapshot.args.isLoadingMainFrame)
275 return; 245 continue;
276 var url = snapshot.args.documentLoaderURL; 246 var url = snapshot.args.documentLoaderURL;
277 if (shouldIgnoreURL(url)) 247 if (shouldIgnoreURL(url))
278 return; 248 continue;
279 var navigationStartEvent = navigationStartFinder. 249 var navigationStartEvent = navigationStartFinder.
280 findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start); 250 findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
281 // Ignore layout w/o preceding navigationStart, as they are not 251 // Ignore layout w/o preceding navigationStart, as they are not
282 // attributed to any time-to-X metric. 252 // attributed to any time-to-X metric.
283 if (navigationStartEvent === undefined) 253 if (navigationStartEvent === undefined)
284 return; 254 continue;
285 255
286 var timeToEvent = ev.start - navigationStartEvent.start; 256 var timeToEvent = ev.start - navigationStartEvent.start;
287 histogram.add(timeToEvent, {url: url}); 257 histogram.add(timeToEvent, {url: url});
288 }, this); 258 }
289 values.addValue(new tr.v.NumericValue( 259 values.addValue(new tr.v.NumericValue(
290 metric.valueName, histogram, 260 metric.valueName, histogram,
291 { description: metric.description })); 261 { description: metric.description }));
292 }, this); 262 }
293 } 263 }
294 264
295 /** 265 /**
296 * Compute significance of given layout event. 266 * Compute significance of given layout event.
297 * 267 *
298 * Significance of a layout is the number of layout objects newly added to the 268 * Significance of a layout is the number of layout objects newly added to the
299 * layout tree, weighted by page height (before and after the layout). 269 * layout tree, weighted by page height (before and after the layout).
300 */ 270 */
301 function layoutSignificance(event) { 271 function layoutSignificance(event) {
302 var newObjects = event.args.counters['LayoutObjectsThatHadNeverHadLayout']; 272 var newObjects = event.args.counters['LayoutObjectsThatHadNeverHadLayout'];
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 var layoutsForFrameId = findAllLayoutEvents(rendererHelper); 338 var layoutsForFrameId = findAllLayoutEvents(rendererHelper);
369 339
370 for (var frameIdRef in layoutsForFrameId) { 340 for (var frameIdRef in layoutsForFrameId) {
371 var navigationStart; 341 var navigationStart;
372 var mostSignificantLayout; 342 var mostSignificantLayout;
373 var maxSignificanceSoFar = 0; 343 var maxSignificanceSoFar = 0;
374 var accumulatedSignificanceWhileHavingBlankText = 0; 344 var accumulatedSignificanceWhileHavingBlankText = 0;
375 345
376 // Iterate over the layout events, remembering one with largest 346 // Iterate over the layout events, remembering one with largest
377 // significance. 347 // significance.
378 layoutsForFrameId[frameIdRef].forEach(function(ev) { 348 for (var ev of layoutsForFrameId[frameIdRef]) {
379 var navigationStartForThisLayout = navigationStartFinder. 349 var navigationStartForThisLayout = navigationStartFinder.
380 findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start); 350 findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
381 // Ignore layout w/o preceding navigationStart, as they are not 351 // Ignore layout w/o preceding navigationStart, as they are not
382 // attributed to any TTFMP. 352 // attributed to any TTFMP.
383 if (navigationStartForThisLayout === undefined) 353 if (navigationStartForThisLayout === undefined)
384 return; 354 continue;
385 355
386 if (navigationStart !== navigationStartForThisLayout) { 356 if (navigationStart !== navigationStartForThisLayout) {
387 // New navigation is found. Compute TTFMP for current navigation, and 357 // New navigation is found. Compute TTFMP for current navigation, and
388 // reset the state variables. 358 // reset the state variables.
389 if (navigationStart !== undefined && 359 if (navigationStart !== undefined &&
390 mostSignificantLayout !== undefined) 360 mostSignificantLayout !== undefined)
391 addFirstMeaningfulPaintSampleToHistogram( 361 addFirstMeaningfulPaintSampleToHistogram(
392 frameIdRef, navigationStart, mostSignificantLayout); 362 frameIdRef, navigationStart, mostSignificantLayout);
393 navigationStart = navigationStartForThisLayout; 363 navigationStart = navigationStartForThisLayout;
394 mostSignificantLayout = undefined; 364 mostSignificantLayout = undefined;
395 maxSignificanceSoFar = 0; 365 maxSignificanceSoFar = 0;
396 accumulatedSignificanceWhileHavingBlankText = 0; 366 accumulatedSignificanceWhileHavingBlankText = 0;
397 } 367 }
398 368
399 // Check if |ev| has the largest significance. If the page has many 369 // Check if |ev| has the largest significance. If the page has many
400 // blank characters, the significance value is accumulated until 370 // blank characters, the significance value is accumulated until
401 // the text become visible. 371 // the text become visible.
402 var significance = layoutSignificance(ev); 372 var significance = layoutSignificance(ev);
403 if (hasTooManyBlankCharactersToBeMeaningful(ev)) { 373 if (hasTooManyBlankCharactersToBeMeaningful(ev)) {
404 accumulatedSignificanceWhileHavingBlankText += significance; 374 accumulatedSignificanceWhileHavingBlankText += significance;
405 } else { 375 } else {
406 significance += accumulatedSignificanceWhileHavingBlankText; 376 significance += accumulatedSignificanceWhileHavingBlankText;
407 accumulatedSignificanceWhileHavingBlankText = 0; 377 accumulatedSignificanceWhileHavingBlankText = 0;
408 if (significance > maxSignificanceSoFar) { 378 if (significance > maxSignificanceSoFar) {
409 maxSignificanceSoFar = significance; 379 maxSignificanceSoFar = significance;
410 mostSignificantLayout = ev; 380 mostSignificantLayout = ev;
411 } 381 }
412 } 382 }
413 }, this); 383 }
414 384
415 // Emit TTFMP for the last navigation. 385 // Emit TTFMP for the last navigation.
416 if (mostSignificantLayout !== undefined) 386 if (mostSignificantLayout !== undefined)
417 addFirstMeaningfulPaintSampleToHistogram( 387 addFirstMeaningfulPaintSampleToHistogram(
418 frameIdRef, navigationStart, mostSignificantLayout); 388 frameIdRef, navigationStart, mostSignificantLayout);
419 } 389 }
420 390
421 values.addValue(new tr.v.NumericValue( 391 values.addValue(new tr.v.NumericValue(
422 'firstMeaningfulPaint', firstMeaningfulPaintHistogram, 392 'firstMeaningfulPaint', firstMeaningfulPaintHistogram,
423 { description: 'time to first meaningful paint' })); 393 { description: 'time to first meaningful paint' }));
424 } 394 }
425 395
426 function firstPaintMetric(values, model) { 396 function firstPaintMetric(values, model) {
427 firstContentfulPaintMetric(values, model); 397 firstContentfulPaintMetric(values, model);
428 firstMeaningfulPaintMetric(values, model); 398 firstMeaningfulPaintMetric(values, model);
429 } 399 }
430 400
431 tr.metrics.MetricRegistry.register(firstPaintMetric); 401 tr.metrics.MetricRegistry.register(firstPaintMetric);
432 402
433 return { 403 return {
434 firstPaintMetric: firstPaintMetric 404 firstPaintMetric: firstPaintMetric
435 }; 405 };
436 }); 406 });
437 </script> 407 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698