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

Side by Side Diff: tracing/tracing/metrics/estimated_input_latency_metric.html

Issue 2323533003: [Not for landing - CL being split] Add Estimated Input Latency - EQT 90th Percentile definition
Patch Set: Review comments + rebase on master Created 4 years, 3 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
(Empty)
1 <!DOCTYPE html>
2 <!--
3 Copyright (c) 2015 The Chromium Authors. All rights reserved.
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: this should be: Copyright 2016 The Chromium
dproy 2016/09/20 01:11:42 Done.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
6 -->
7
8 <link rel="import" href="/tracing/base/category_util.html">
9 <link rel="import" href="/tracing/metrics/metric_registry.html">
10 <link rel="import" href="/tracing/metrics/system_health/utils.html">
11 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
12 <link rel="import" href="/tracing/model/user_model/load_expectation.html">
13 <link rel="import" href="/tracing/value/histogram.html">
14
15 <script>
16 'use strict';
17
18 tr.exportTo('tr.metrics', function() {
19
20 var TOPLEVEL_CATEGORY_NAME = 'toplevel';
21
22 // TODO(dproy): Remove after we close #2784
23 function hasCategoryAndName(event, category, title) {
24 return event.title === title && event.category &&
25 tr.b.getCategoryParts(event.category).indexOf(category) !== -1;
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: line continuations are indented by 4 characte
dproy 2016/09/20 01:11:42 Done.
26 }
27
28 function runConditionallyOnInnermostDescendants(slice, predicate, cb) {
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: what is an innermost descendant? Are these li
dproy 2016/09/20 01:11:43 This function is a little unfortunately named but
benjhayden 2016/09/20 05:52:35 Thanks for the explanation! Would it be possible t
dproy 2016/09/20 15:21:06 One way to get around this would be to just look f
29 var succeededOnSomeDescendant = false;
30 for (var child of slice.subSlices) {
31 var succeededOnThisChild = runConditionallyOnInnermostDescendants(
32 child, predicate, cb);
charliea (OOO until 10-5) 2016/09/19 14:35:33 same (line continuations)
dproy 2016/09/20 01:11:43 Done.
33 succeededOnSomeDescendant =
34 succeededOnThisChild || succeededOnSomeDescendant;
charliea (OOO until 10-5) 2016/09/19 14:35:33 same (line continuations)
dproy 2016/09/20 01:11:43 Done.
35 }
36
37 if (succeededOnSomeDescendant) {
38 return true;
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: no need for braces around a single line branc
dproy 2016/09/20 01:11:43 Does our style guide forbid this? I really dislike
benjhayden 2016/09/20 05:52:35 For what it's worth, Ethan and I also wish that th
39 }
40
41 if (!predicate(slice)) {
42 return false;
charliea (OOO until 10-5) 2016/09/19 14:35:33 same (single line branch)
43 }
44
45 cb(slice);
46 return true;
47 }
48
49 function forEachInnermostTopLevelSlices(thread, cb) {
50 var topLevelPredicate = slice => tr.b.getCategoryParts(slice.category)
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: I don't think we ever break at the ., but ins
dproy 2016/09/20 01:11:42 Done.
51 .includes(TOPLEVEL_CATEGORY_NAME);
52
53 for (var slice of thread.sliceGroup.topLevelSlices) {
charliea (OOO until 10-5) 2016/09/19 14:35:33 same (no need for braces)
54 runConditionallyOnInnermostDescendants(slice, topLevelPredicate, cb);
55 }
56 }
57
58 function getAllInteractiveTimestampsSorted(model) {
59 // TODO(dproy): When LoadExpectation v.1.0 is released,
60 // update this function to use the new LoadExpectation rather
61 // than calling loading_metric.html.
62
63 var values = new tr.v.ValueSet();
64 tr.metrics.sh.loadingMetric(values, model);
65 var ttiValues = values.getValuesNamed('timeToFirstInteractive');
charliea (OOO until 10-5) 2016/09/19 14:35:32 wrong indentation?
charliea (OOO until 10-5) 2016/09/19 14:35:32 wrong indentation?
dproy 2016/09/20 01:11:42 Done.
66 var interactiveTsList = [];
67 for (var bin of tr.b.getOnlyElement(ttiValues).allBins) {
68 for (var diagnostics of bin.diagnosticMaps) {
69 var info = diagnostics.get('Navigation infos');
70 interactiveTsList.push(info.value.interactive);
71 }
72 }
73 return interactiveTsList.sort((x, y) => x - y);
74 }
75
76 function getAllNavStartTimesSorted(rendererHelper) {
77 var list = [];
78 for (var ev of rendererHelper.mainThread.sliceGroup.childEvents()) {
79 if (!hasCategoryAndName(ev, 'blink.user_timing', 'navigationStart'))
80 continue;
81 list.push(ev.start);
82 }
83 return list.sort((x, y) => x - y);
84 }
85
86 // A task window is defined as time from TTI until either
87 // 1. beginning of next navigationStart event, or
88 // 2. end of traces
89 function getTaskWindows(interactiveTsList, navStartTimeList, endOfTraces) {
90 var curNavStartTimeIndex = 0;
91 var endOfLastWindow = -Infinity;
92 var taskWindows = [];
93 for (var curTTI of interactiveTsList) {
94 var curNavStartTime = navStartTimeList[curNavStartTimeIndex];
95 while (curNavStartTime !== undefined && curNavStartTime < curTTI) {
96 // There are possibly multiple navigationStart timestamps between
97 // two interactive timestamps - the previous page load could
98 // never reach interactive status.
99 curNavStartTimeIndex++;
100 curNavStartTime = navStartTimeList[curNavStartTimeIndex];
101 }
102
103 if (curNavStartTime === endOfLastWindow) {
104 // This is a violation of core assumption.
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: not need for braces
105 // TODO: When two pages share a render process, we can possibly
106 // have two interactive time stamps between two navigation events.
107 // If both interactive timestamps are reported, it is not clear how
108 // to define estimated input latency.
109 throw new Error("Two TTI timestamps with no navigation between them");
110 }
111
112 if (curNavStartTime === undefined) {
113 taskWindows.push({start: curTTI, end: endOfTraces});
114 endOfLastWindow = endOfTraces;
115 continue;
116 }
117
118 taskWindows.push({start: curTTI, end: curNavStartTime});
119 endOfLastWindow = curNavStartTime;
120 }
121 return taskWindows;
122 }
123
124 /**
125 * Note: Taken from
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: the first line of a jsdoc should be what the
dproy 2016/09/20 01:11:42 Done.
126 * https://github.com/GoogleChrome/lighthouse/blob/a5bbe2338fa474c94bb87584940 8704c81fec3df/lighthouse-core/lib/traces/tracing-processor.js#L121
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: please create bit.ly or goo.gl shortlink and
dproy 2016/09/20 01:11:42 Done.
127 *
128 * Calculate duration at specified percentiles for given population of
charliea (OOO until 10-5) 2016/09/19 14:35:32 I'm not sure I understand what duration we're calc
dproy 2016/09/20 01:11:42 Clarified.
129 * durations.
130 * If one of the durations overlaps the end of the window, the full
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: if you want different paragraphs within a jsd
dproy 2016/09/20 01:11:42 Done.
131 * duration should be in the duration array, but the length not included
132 * within the window should be given as `clippedLength`. For instance, if a
133 * 50ms duration occurs 10ms before the end of the window, `50` should be in
134 * the `durations` array, and `clippedLength` should be set to 40.
135 * @see https://docs.google.com/document/d/18gvP-CBA2BiBpi3Rz1I1ISciKGhniTSZ9T Y0XCnXS7E/preview
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: line is too long. Please create a shortlink t
dproy 2016/09/20 01:11:42 Done.
136 */
137 function calculateEILRiskPercentiles(
138 durations, totalTime, percentiles, clippedLength) {
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: line continuations get four indents
dproy 2016/09/20 01:11:42 Done.
139 clippedLength = clippedLength || 0;
140
141 var busyTime = tr.b.Statistics.sum(durations);
142 busyTime -= clippedLength;
143
144 // Start with idle time already compvare.
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: compvare => compare
benjhayden 2016/09/19 20:00:48 Actually, I think this is supposed to be "complete
dproy 2016/09/20 01:11:42 Yes this was indeed complete. s/let/var got me aga
145 var completedTime = totalTime - busyTime;
146 var duration = 0;
147 var cdfTime = completedTime;
charliea (OOO until 10-5) 2016/09/19 14:35:33 I can kind of vaguely guess what cdfTime is, but I
dproy 2016/09/20 01:11:42 I didn't write this code, and I'm finding it very
148 var results = new Map();
149
150 var durationIndex = -1;
151 var remainingCount = durations.length + 1;
152 if (clippedLength > 0) {
153 // If there was a clipped duration, one less in count
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: no need for braces
154 // since one hasn't started yet.
155 remainingCount--;
156 }
157
158 // Find percentiles of interest, in order.
159 for (var percentile of percentiles) {
160 // Loop over durations, calculating a CDF value for each until it is above
161 // the target percentile.
162 var percentileTime = percentile * totalTime;
163 while (cdfTime < percentileTime && durationIndex < durations.length - 1) {
164 completedTime += duration;
165 remainingCount += (duration >= 0 ? -1 : 1);
166
167 if (clippedLength > 0 && clippedLength < durations[durationIndex + 1]) {
168 duration = -clippedLength;
169 clippedLength = 0;
170 } else {
171 durationIndex++;
172 duration = durations[durationIndex];
173 }
174
175 // Calculate value of CDF (multiplied by totalTime) for the end of
176 // this duration.
177 cdfTime = completedTime + Math.abs(duration) * remainingCount;
178 }
179
180 // Negative results are within idle time (0ms wait by definition),
181 // so clamp at zero.
182 results.set(
183 percentile,
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: line continuations get four indents
dproy 2016/09/20 01:11:42 Done.
184 Math.max(0, (percentileTime - completedTime) / remainingCount));
185 }
186
187 return results;
188 }
189
190 /**
191 * Note: This is adapted from
192 * https://github.com/GoogleChrome/lighthouse/blob/a5bbe2338fa474c94bb87584940 8704c81fec3df/lighthouse-core/lib/traces/tracing-processor.js#L185
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: shortlink.
dproy 2016/09/20 01:11:42 Done.
193 */
194 function getEQTPercentilesForWindow(
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: what the heck is an EQT?
dproy 2016/09/20 01:11:42 Added comments
195 percentiles, rendererHelper, startTime, endTime) {
196 var totalTime = endTime - startTime;
197 percentiles.sort((a, b) => a - b);
198
199 var durations = [];
200 var clippedLength = 0;
201 forEachInnermostTopLevelSlices(rendererHelper.mainThread, slice => {
202 // Discard slices outside range.
203 if (slice.end <= startTime || slice.start >= endTime) {
204 return;
205 }
206
207 // Clip any at edges of range.
208 var duration = slice.duration;
209 var sliceStart = slice.start;
210 if (sliceStart < startTime) {
211 // Any part of task before window can be discarded.
212 sliceStart = startTime;
213 duration = slice.end - sliceStart;
214
215 }
216 if (slice.end > endTime) {
217 // Any part of task after window must be clipped but accounted for.
218 clippedLength = duration - (endTime - sliceStart);
219 }
220 durations.push(duration);
221
222 });
223 durations.sort((a, b) => a - b);
224 return calculateEILRiskPercentiles(
225 durations, totalTime, percentiles, clippedLength);
226 }
227
228 /**
229 * @param {!tr.v.ValueSet} values
230 * @param {!tr.model.Model} model
231 * @param {!Object=} opt_options
charliea (OOO until 10-5) 2016/09/19 14:35:32 what type of options are available? This might als
benjhayden 2016/09/19 20:00:48 This metric doesn't support any opt_options, so I
dproy 2016/09/20 01:11:42 Let me know if I should remove opt_options altoget
232 */
233 function estimatedInputLatencyMetric(values, model, opt_options) {
234
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: unnecessary blank line
dproy 2016/09/20 01:11:43 Done.
235 var chromeHelper = model.getOrCreateHelper(
236 tr.model.helpers.ChromeModelHelper);
237 // The largest pid renderer is probably the one we're interested in
238 var rendererHelper = chromeHelper.rendererWithLargestPid;
239
240 var interactiveTimestamps = getAllInteractiveTimestampsSorted(model);
241
242 // We're assuming children iframes will never emit navigationStart events
243 var navStartTimeList = getAllNavStartTimesSorted(rendererHelper);
244 var taskWindowList = getTaskWindows(
245 interactiveTimestamps,
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
246 navStartTimeList,
247 rendererHelper.mainThread.bounds.max);
248
249 // Compute the 90th percentile
250 var eqtTargetPercentiles = [0.9];
251
252 var eqt90thPercentile = new tr.v.Histogram(
253 'Expected Queueing Time 90th Percentile',
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: line continuations
dproy 2016/09/20 01:11:42 Done.
254 tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
255 tr.v.HistogramBinBoundaries.createExponential(0.1, 1e3, 100));
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: I think the best practice is to create these
dproy 2016/09/20 01:11:43 Done: made these top level constants with some com
256
257 for (var taskWindow of taskWindowList) {
258 var eqtPercentiles = getEQTPercentilesForWindow(
259 eqtTargetPercentiles, rendererHelper, taskWindow.start, taskWindow.end);
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
260 var eqt90th = eqtPercentiles.get(0.9);
261 if (eqt90th !== undefined) {
262 eqt90thPercentile.addSample(eqt90th);
charliea (OOO until 10-5) 2016/09/19 14:35:32 nit: single line branch
263 }
264 }
265
266 values.addHistogram(eqt90thPercentile);
267 }
268
269 tr.metrics.MetricRegistry.register(estimatedInputLatencyMetric, {
270 supportsRangeOfInterest: false
271 });
272
273 return {
274 estimatedInputLatencyMetric: estimatedInputLatencyMetric,
275 calculateEILRiskPercentiles: calculateEILRiskPercentiles,
276 getEQTPercentilesForWindow: getEQTPercentilesForWindow
277 };
278 });
279 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698