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

Side by Side Diff: tracing/tracing/metrics/system_health/first_paint_metric.html

Issue 1963583005: Rewrite firstPaintMetric to support extracting multiple navigations from a single trace (Closed) Base URL: https://chromium.googlesource.com/external/github.com/catapult-project/catapult.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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">
11 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> 11 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
12 <link rel="import" href="/tracing/value/numeric.html"> 12 <link rel="import" href="/tracing/value/numeric.html">
13 <link rel="import" href="/tracing/value/value.html"> 13 <link rel="import" href="/tracing/value/value.html">
14 14
15 <script> 15 <script>
16 'use strict'; 16 'use strict';
17 17
18 tr.exportTo('tr.metrics.sh', function() { 18 tr.exportTo('tr.metrics.sh', function() {
19 var timeDurationInMs_smallerIsBetter = 19 var timeDurationInMs_smallerIsBetter =
20 tr.v.Unit.byName.timeDurationInMs_smallerIsBetter; 20 tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;
21 21
22 function findTargetRendererHelper(model) { 22 function findTargetRendererHelper(chromeHelper) {
23 var chromeHelper = model.getOrCreateHelper(
24 tr.model.helpers.ChromeModelHelper);
25
26 var largestPid = -1; 23 var largestPid = -1;
27 for (var pid in chromeHelper.rendererHelpers) { 24 for (var pid in chromeHelper.rendererHelpers) {
28 var rendererHelper = chromeHelper.rendererHelpers[pid]; 25 var rendererHelper = chromeHelper.rendererHelpers[pid];
29 if (rendererHelper.isChromeTracingUI) 26 if (rendererHelper.isChromeTracingUI)
30 continue; 27 continue;
31 if (pid > largestPid) 28 if (pid > largestPid)
32 largestPid = pid; 29 largestPid = pid;
33 } 30 }
34 31
35 if (largestPid === -1) 32 if (largestPid === -1)
36 return undefined; 33 return undefined;
37 34
38 return chromeHelper.rendererHelpers[largestPid]; 35 return chromeHelper.rendererHelpers[largestPid];
39 } 36 }
40 37
41 function findNavigationStartEvent(rendererHelper) { 38 function navigationStartFinder(rendererHelper) {
42 var navigationStartEvent = undefined; 39 var navigationStartsForFrameId = {};
43
44 rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer( 40 rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer(
45 () => true, function(ev) { 41 () => true, function(ev) {
46 if (navigationStartEvent !== undefined || 42 if (ev.category !== 'blink.user_timing' ||
47 ev.category !== 'blink.user_timing') 43 ev.title !== 'navigationStart')
48 return; 44 return;
49 if (ev.title === 'navigationStart') 45
50 navigationStartEvent = ev; 46 var frameIdRef = ev.args['frame'];
47 var list = navigationStartsForFrameId[frameIdRef];
48 if (list === undefined) {
49 navigationStartsForFrameId[frameIdRef] = list = [];
50 }
51 list.unshift(ev);
51 }, 52 },
52 this); 53 this);
53 54
54 return navigationStartEvent; 55 return function findNavigationStartEventForFrameBeforeTimestamp(frameIdRef,
56 ts) {
57 var list = navigationStartsForFrameId[frameIdRef];
58 if (list === undefined)
59 throw new Error('No navigationStartEvent found for frame id "' +
60 frameIdRef + '"');
61
62 var eventBeforeTimestamp;
63 list.forEach(function(ev) {
64 if (ev.start > ts)
65 return;
66
67 if (eventBeforeTimestamp === undefined)
68 eventBeforeTimestamp = ev;
69 }, this);
70 if (eventBeforeTimestamp === undefined)
71 throw new Error('Failed to find navigationStartEvent.');
72 return eventBeforeTimestamp;
73 }
55 } 74 }
56 75
57 function findFirstPaintEvent(rendererHelper, title, frame) { 76 function findUrlOfFrameAt(rendererHelper, frameIdRef, ts) {
58 var firstPaintEvent = undefined; 77 var url;
78
79 var objects = rendererHelper.process.objects;
80 var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader'];
81 frameLoaderInstances.forEach(function(instance) {
82 var snapshot = instance.getSnapshotAt(ts);
83 if (frameIdRef !== snapshot.args['frame']['id_ref'])
84 return;
85
86 url = snapshot.args['documentLoaderURL'];
87 }, this);
88
89 return url;
90 }
91
92 function findFirstPaintEvents(rendererHelper, title) {
93 var firstPaintEvents = [];
59 94
60 rendererHelper.process.iterateAllEvents( 95 rendererHelper.process.iterateAllEvents(
61 function(ev) { 96 function(ev) {
62 if (firstPaintEvent !== undefined || 97 if (ev.category !== 'blink.user_timing' ||
63 ev.category !== 'blink.user_timing' || 98 ev.title !== title)
64 ev.title !== title ||
65 ev.args === undefined || ev.args['frame'] !== frame)
66 return; 99 return;
67 100
68 firstPaintEvent = ev; 101 firstPaintEvents.push(ev);
69 }, this); 102 }, this);
70 103
71 return firstPaintEvent; 104 return firstPaintEvents;
105 }
106
107 function prepareTelemetryInternalEventPredicate(rendererHelper) {
108 var ignoreRegionSlices = [];
109 rendererHelper.mainThread.asyncSliceGroup.iterateAllEventsInThisContainer(
110 () => true, function(slice) {
111 if (slice.title.match(/^telemetry\.internal/))
112 ignoreRegionSlices.push(slice);
113 }, this);
114
115 return function isTelemetryInternalEvent(slice) {
116 for (var i = 0; i < ignoreRegionSlices.length; ++ i) {
117 if (ignoreRegionSlices[i].bounds(slice))
118 return true;
119 }
120 return false;
121 }
72 } 122 }
73 123
74 function firstPaintMetric(valueList, model) { 124 function firstPaintMetric(valueList, model) {
75 var rendererHelper = findTargetRendererHelper(model); 125 var chromeHelper = model.getOrCreateHelper(
76 var navigationStartEvent = findNavigationStartEvent(rendererHelper); 126 tr.model.helpers.ChromeModelHelper);
127 var rendererHelper = findTargetRendererHelper(chromeHelper);
128 var isTelemetryInternalEvent =
129 prepareTelemetryInternalEventPredicate(rendererHelper);
130 var findNavigationStartEventForFrameBeforeTimestamp =
131 navigationStartFinder(rendererHelper);
77 132
78 if (navigationStartEvent === undefined) 133 var firstPaintEvents = findFirstPaintEvents(rendererHelper,
79 throw new Error('Failed to find navigationStartEvent.'); 134 'firstContentfulPaint');
135 firstPaintEvents = firstPaintEvents.filter(
136 (ev) => !isTelemetryInternalEvent(ev));
137 firstPaintEvents.forEach(function(ev) {
138 var frameIdRef = ev.args['frame'];
139 var url = findUrlOfFrameAt(rendererHelper, frameIdRef, ev.start);
140 var navigationStartEvent =
141 findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
80 142
81 var frame = navigationStartEvent.args['frame']; 143 var timeToFirstContentfulPaint =
82 var firstContentfulPaintEvent = findFirstPaintEvent(rendererHelper, 144 ev.start - navigationStartEvent.start;
83 'firstContentfulPaint', frame);
84 if (firstContentfulPaintEvent === undefined)
85 throw new Error(
86 'Failed to find firstContentfulPaintEvent for frame ' + frame);
87 145
88 var grouping_keys = {}; 146 var grouping_keys = {url: url};
89 147 valueList.addValue(new tr.v.NumericValue(
benjhayden 2016/05/10 19:54:46 Instead of several scalars, do you want to use a N
kouhei (in TOK) 2016/05/11 06:39:33 I think we want separate individual values, as his
nednguyen 2016/05/11 21:36:38 Why do you think the histogram doesn't make sense?
kouhei (in TOK) 2016/05/12 05:41:25 Added Numeric histogram, but not sure how we can u
nednguyen 2016/05/12 15:35:30 For future use cases of Pcv2, I can imagine we hav
90 var timeToFirstContentfulPaint = 148 model.canonicalUrlThatCreatedThisTrace, 'firstContentfulPaint',
benjhayden 2016/05/10 20:25:43 This is spelled "model.canonicalUrl" now.
kouhei (in TOK) 2016/05/11 06:39:33 Done.
91 firstContentfulPaintEvent.start - navigationStartEvent.start; 149 new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter,
92 valueList.addValue(new tr.v.NumericValue( 150 timeToFirstContentfulPaint),
93 model.canonicalUrlThatCreatedThisTrace, 'firstContentfulPaint', 151 { description: 'time to first contentful paint' },
94 new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter, 152 grouping_keys));
95 timeToFirstContentfulPaint), 153 }, this);
96 { description: 'time to first contentful paint' },
97 grouping_keys));
98 } 154 }
99 155
100 firstPaintMetric.prototype = { 156 firstPaintMetric.prototype = {
101 __proto__: Function.prototype 157 __proto__: Function.prototype
102 }; 158 };
103 159
104 tr.metrics.MetricRegistry.register(firstPaintMetric); 160 tr.metrics.MetricRegistry.register(firstPaintMetric);
105 161
106 return { 162 return {
107 firstPaintMetric: firstPaintMetric 163 firstPaintMetric: firstPaintMetric
108 }; 164 };
109 }); 165 });
110 </script> 166 </script>
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698