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

Side by Side Diff: tracing/tracing/metrics/estimated_input_latency_metric_test.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) 2016 The Chromium Authors. All rights reserved.
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/core/test_utils.html">
9 <link rel="import" href="/tracing/metrics/estimated_input_latency_metric.html">
10 <link rel="import" href="/tracing/metrics/system_health/loading_metric.html">
11 <link rel="import" href="/tracing/value/value_set.html">
12
13 <script>
14 'use strict';
15
16 tr.b.unittest.testSuite(function() {
17 var FPTOLERANCE = 0.1;
charliea (OOO until 10-5) 2016/09/19 14:35:34 no need for this constant. Just about everywhere e
dproy 2016/09/20 01:11:43 Done.
18 var MAIN_THREAD_ID = 2;
19 var INTERACTIVE_WINDOW_SIZE_MS = tr.metrics.sh.INTERACTIVE_WINDOW_SIZE_MS;
20 var calculateEILRiskPercentiles = tr.metrics.calculateEILRiskPercentiles;
21
22 function newSchedulerTask(startTime, duration) {
23 return tr.c.TestUtils.newSliceEx({
24 cat: 'toplevel',
25 title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
26 start: startTime,
27 duration: duration
28 });
29 }
30
31 function assertTasksNotTooLong(tti, taskList) {
32 // Need to make sure the tasks in the interactive window are less that
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: comments in tracing/ are complete sentences t
33 // responsiveness threshold because otherwise it will push back TTI.
34 // If we change RESPONSIVENESS_THRESHOLD_MS or INTERACTIVE_WINDOW_SIZE_MS in
35 // TTI we may have to change the task durations for this test.
36 for (var task of taskList) {
37 if (task.start < tti + INTERACTIVE_WINDOW_SIZE_MS) {
38 assert.isBelow(
39 task.duration, tr.metrics.sh.RESPONSIVENESS_THRESHOLD_MS);
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
40 }
41 }
42 }
43
44 function addTasksToThread(mainThread, tti, taskList) {
45 assertTasksNotTooLong(tti, taskList);
46 for (var task of taskList) {
47 mainThread.sliceGroup.pushSlice(
48 newSchedulerTask(task.start, task.duration));
49 }
50 }
51
52 function createTestModel(rendererCallback) {
53 var model = tr.c.TestUtils.newModel(function(model) {
54 var rendererProcess = model.getOrCreateProcess(1);
55 var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
56 mainThread.name = 'CrRendererMain';
57 rendererCallback(rendererProcess);
58 });
59 return model;
60 }
61
62 function addTestFrame(rendererProcess) {
63 // We need FMP for TTI, and FMP needs to reference a frame.
64 rendererProcess.objects.addSnapshot(
65 'ptr', 'loading', 'FrameLoader', 300,
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
66 {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
67 documentLoaderURL: 'http://example.com'});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: wrong indent here
dproy 2016/09/20 01:11:43 What's the correct indent here? Line 67 shifted fo
68 }
69
70 function addInteractiveWindow(
71 rendererProcess, startNavigationTime, ttiTime) {
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
72 // To get to TTI, we need a firstMeaningfulPaint and a sufficiently large
73 // window of no long tasks.
74 var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
75 mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
76 cat: 'blink.user_timing',
77 title: 'navigationStart',
78 start: startNavigationTime,
79 duration: 0.0,
80 args: {frame: '0xdeadbeef'}
81 }));
82
83 mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
84 cat: 'loading',
85 title: 'firstMeaningfulPaintCandidate',
86 start: ttiTime,
87 duration: 0.0,
88 args: {frame: '0xdeadbeef'}
89 }));
90
91 // Add a 0 duration task at the end so we hit the required window size.
92 mainThread.sliceGroup.pushSlice(
93 newSchedulerTask(ttiTime + INTERACTIVE_WINDOW_SIZE_MS, 0));
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: line continuations
dproy 2016/09/20 01:11:43 Done.
94 }
95
96 function prepareModelForSingleWindowTest(tti, postTTITasks) {
97 var model = createTestModel(rendererProcess => {
98 var startNavTime = 0;
99 addTestFrame(rendererProcess);
100 addInteractiveWindow(rendererProcess, startNavTime, tti);
101 var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
102 addTasksToThread(mainThread, tti, postTTITasks);
103 });
104 return model;
105 }
106
107 function computeEQT90Numeric(model) {
108 var values = new tr.v.ValueSet();
109 tr.metrics.estimatedInputLatencyMetric(values, model);
110 var numeric = tr.b.getOnlyElement(values.getValuesNamed(
111 'Expected Queueing Time 90th Percentile'));
charliea (OOO until 10-5) 2016/09/19 14:35:34 same
dproy 2016/09/20 01:11:43 Done.
112 return numeric;
113 }
114
115 test('eqt90thPercentileTest40msFull', function() {
116 var tti = 1000;
117 var postTTITasks = [];
118 var taskDur = 40;
119 var windowEnd = tti + INTERACTIVE_WINDOW_SIZE_MS;
120 for (var startTime = tti; startTime < windowEnd; startTime += taskDur) {
121 postTTITasks.push({start: startTime, duration: taskDur});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for braces in one line branch
122 }
123
124 var model = prepareModelForSingleWindowTest(tti, postTTITasks);
125 var numeric = computeEQT90Numeric(model);
126 assert.equal(numeric.running.count, 1);
127 assert.closeTo(numeric.running.mean, 36, FPTOLERANCE);
128 });
129
130 test('eqt90thPercentileTestZeroEQT', function() {
131 var tti = 1000;
132 var postTTITasks = []; // No tasks after TTI
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: comments in TV are a complete sentence that e
133 var model = prepareModelForSingleWindowTest(tti, postTTITasks);
134 var numeric = computeEQT90Numeric(model);
135 assert.equal(numeric.running.count, 1);
136 assert.equal(numeric.running.mean, 0);
137 });
138
139 test('eqt90thPercentileTestLargePostTTITask', function() {
140 var tti = 1000;
141 var postTTITasks = [
142 {start: tti + INTERACTIVE_WINDOW_SIZE_MS, duration: 5000}
143 ];
144
145 var model = prepareModelForSingleWindowTest(tti, postTTITasks);
146 var numeric = computeEQT90Numeric(model);
147 assert.equal(numeric.running.count, 1);
148 assert.closeTo(numeric.running.mean, 4000, FPTOLERANCE);
149 });
150
151 test('eqt90thPercentileTestAlternate40ms', function() {
152 var tti = 1000;
153 var postTTITasks = [];
154 var taskDur = 40;
155 var windowEnd = tti + INTERACTIVE_WINDOW_SIZE_MS;
156 for (var startTime = tti; startTime < windowEnd; startTime += 2 * taskDur) {
157 postTTITasks.push({start: startTime, duration: taskDur});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: one line branch
158 }
159 var model = prepareModelForSingleWindowTest(tti, postTTITasks);
160 var numeric = computeEQT90Numeric(model);
161 assert.equal(numeric.running.count, 1);
162 assert.closeTo(numeric.running.mean, 32, FPTOLERANCE);
163 });
164
165 test('eqt90thPercentileMultipleWindows', function() {
166 // There are five interactive windows:
167 // window 1 - 3 have zero tasks
168 // window 4 is full of back to back 40 ms tasks
169 // window 5 has alternating 40ms task and 40ms idleTime
170
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: no need for blank line
dproy 2016/09/20 01:11:43 Done.
171 var model = createTestModel(rendererProcess => {
172 addTestFrame(rendererProcess);
173 var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
174
175 for (var i = 0; i < 5; i++) {
176 var startNavigationTime = i * 10000;
177 var ttiTime = startNavigationTime + 1000;
178 var windowEnd = (i + 1) * 10000;
179 addInteractiveWindow(
180 rendererProcess, startNavigationTime, ttiTime, windowEnd);
181 }
182
183 var taskDur = 40;
184 var win4Tasks = [];
185 var win4Interactive = 31000;
186 var win4End = 40000;
187 for (var startTime = win4Interactive;
188 startTime < win4End; startTime += taskDur) {
189 win4Tasks.push({start: startTime, duration: taskDur});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for braces
190 }
191 addTasksToThread(mainThread, win4Interactive, win4Tasks);
192
193 var win5Tasks = [];
194 var win5Interactive = 41000;
195 var win5End = 50000;
196 for (var startTime = win5Interactive;
197 startTime < win5End; startTime += 2 * taskDur) {
198 win5Tasks.push({start: startTime, duration: taskDur});
199 }
200 addTasksToThread(mainThread, win5Interactive, win5Tasks);
201 });
202
203 var numeric = computeEQT90Numeric(model);
204 assert.equal(numeric.running.count, 5);
205 numeric.sampleValues.slice(0, 3).forEach(v => assert.equal(v, 0));
206 assert.closeTo(numeric.sampleValues[3], 36, FPTOLERANCE);
207 assert.closeTo(numeric.sampleValues[4], 32, FPTOLERANCE);
208 });
209
210 test('properlyIterateSchedulerTasks', function() {
211 // Test that we handle both top level message loop tasks and nested renderer
212 // scheduler tasks. We add 2000ms worth of back to back 40ms
213 // MessageLoop::RunTask slices with no nested scheduler task, and then one
214 // big 3000ms MessageLoop::RunTask with 2000ms worth of back to back 40ms
215 // nested scheduler tasks inside.
216
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for blank line
dproy 2016/09/20 01:11:43 Done.
217 var messageLoopTaskTitle = 'MessageLoop::RunTask';
218 var schedulerTaskTitle = 'TaskQueueManager::ProcessTaskFromWorkQueue';
219 var model = createTestModel(rendererProcess => {
220 var startNavTime = 0;
221 var tti = 1000;
222 var taskDur = 40;
223 assert.isBelow(taskDur, tr.metrics.sh.RESPONSIVENESS_THRESHOLD_MS);
224
225 addTestFrame(rendererProcess);
226 addInteractiveWindow(rendererProcess, startNavTime, tti);
227 var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
228
229 for (var start = tti; start < tti + 2000; start += taskDur) {
230 mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
231 cat: 'toplevel',
232 title: messageLoopTaskTitle,
233 start: start,
234 duration: taskDur
235 }));
236 }
237
238 // A huge ML task with back to back 40ms tasks in scheduler
239 var giantMessageLoopSlice = tr.c.TestUtils.newSliceEx({
240 cat: 'toplevel',
241 title: messageLoopTaskTitle,
242 start: 3000,
243 duration: 3000
244 });
245
246 // back to back for 3000
247 var schedulerDoWork = tr.c.TestUtils.newSliceEx({
248 cat: 'not-toplevel',
249 title: 'TaskQueueManager::DoWork',
250 start: 3500,
251 duration: 2000
252 });
253
254 for (var start = 3500; start < 3500 + 2000; start += taskDur) {
255 schedulerDoWork.subSlices.push(newSchedulerTask(start, taskDur));
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for braces
256 }
257
258 giantMessageLoopSlice.subSlices.push(schedulerDoWork);
259 mainThread.sliceGroup.pushSlice(giantMessageLoopSlice);
260 })
261
262 var numeric = computeEQT90Numeric(model);
263 assert.equal(numeric.running.count, 1);
264 assert.closeTo(numeric.running.mean, 30, FPTOLERANCE);
265 });
266
267
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: extra blank line
dproy 2016/09/20 01:11:43 Done.
268 // riskPercentiles tests ported from Lighthouse
269 var defaultPercentiles = [0, .25, .50, .75, .90, .99, 1];
270
271 function verifyAllResults(results, expected) {
272 for (var i = 0; i < defaultPercentiles.length; i++) {
273 var computedEqt = results.get(defaultPercentiles[i]);
274 var expectedEqt = expected[i];
275 console.log(results, expected, i);
276 assert.closeTo(computedEqt, expectedEqt, FPTOLERANCE);
277 }
278 }
279
280 test('riskPercentiles.PercentileOfNoTasks', () => {
281 var results = calculateEILRiskPercentiles([], 100, defaultPercentiles);
282 var expected = [0, 0, 0, 0, 0, 0, 0];
283 verifyAllResults(results, expected);
284 });
285
286 test('riskPercentiles.singleTaskWithIdleTime', () => {
287 var results = calculateEILRiskPercentiles([50], 100, defaultPercentiles);
288 var expected = [0, 0, 0, 25, 40, 49, 50];
289 verifyAllResults(results, expected);
290 });
291
292 test('riskPercentiles.singleTaskNoIdleTime', () => {
293 var results = calculateEILRiskPercentiles([50], 50, defaultPercentiles);
294 var expected = [0, 12.5, 25, 37.5, 45, 49.5, 50];
295 verifyAllResults(results, expected);
296 });
297
298 test('riskPercentiles.severalEqualLengthTasks', () => {
299 var results = calculateEILRiskPercentiles(
300 [50, 50, 50, 50], 400, defaultPercentiles);
301 var expected = [0, 0, 0, 25, 40, 49, 50];
302 verifyAllResults(results, expected);
303 });
304
305 test('riskPercentiles.zeroDurationTask', () => {
306 var results = calculateEILRiskPercentiles(
307 [0, 0, 0, 10, 20, 20, 30, 30, 120], 320, defaultPercentiles);
308 var expected = [0, 0, 12, 40, 88, 116.8, 120];
309 verifyAllResults(results, expected);
310 });
311
312 test('riskPercentiles.threeOneSecondInFiveSecondWindow', () => {
313 // Three tasks of one second each, all within a five-second window.
314 // Mean Queueing Time of 300ms.
315 var results = calculateEILRiskPercentiles(
316 [1000, 1000, 1000], 5000, defaultPercentiles, 0);
317 var expected = [0, 0, 166.67, 583.33, 833.33, 983.33, 1000];
318 verifyAllResults(results, expected);
319 });
320
321 test('riskPercentiles.clippedTask', () => {
322 var results = calculateEILRiskPercentiles(
323 [10, 20, 50, 60, 90, 100], 300, defaultPercentiles, 30);
324 var expected = [0, 16.25, 37.5, 58.33, 80, 97, 100];
325 verifyAllResults(results, expected);
326
327 });
328
329 test('riskPercentiles.singleTaskOverMultipleWindows', () => {
330 // One 20 second long task over three five-second windows.
331
332 // Starts 3 seconds into the first window. Mean Queueing Time = 7600ms.
333 var TASK_LENGTH = 20000;
334 let results1 = calculateEILRiskPercentiles(
335 [TASK_LENGTH], 5000, defaultPercentiles, TASK_LENGTH - 2000);
336 var expected1 = [0, 0, 0, 18750, 19500, 19950, 20000];
337 verifyAllResults(results1, expected1);
338
339 // Starts 2 seconds before and ends 13 seconds after.
340 // Mean Queueing Time = 15500ms.
341 var results2 = calculateEILRiskPercentiles(
342 [TASK_LENGTH - 2000], 5000, defaultPercentiles, TASK_LENGTH - 7000);
343 var expected2 = [0, 14250, 15500, 16750, 17500, 17950, 18000];
344 verifyAllResults(results2, expected2);
345
346 // Starts 17 seconds before and ends 3 seconds into the window.
347 // Mean Queueing Time = 900ms.
348 var results3 = calculateEILRiskPercentiles(
349 [TASK_LENGTH - 17000], 5000, defaultPercentiles, 0);
350 var expected3 = [0, 0, 500, 1750, 2500, 2950, 3000];
351 verifyAllResults(results3, expected3);
352 });
353
354 test('riskPercentiles.oneTaskShorterThanClippedLengthOfAnother', () => {
355 var results = calculateEILRiskPercentiles(
356 [40, 100], 100, defaultPercentiles, 50);
357 var expected = [0, 15, 40, 75, 90, 99, 100];
358 verifyAllResults(results, expected);
359 });
360
361 test('riskPercentiles.completelyClippedTask', () => {
362 var results = calculateEILRiskPercentiles(
363 [40, 100], 100, defaultPercentiles, 100);
364 var expected = [0, 0, 0, 15, 30, 39, 40];
365 verifyAllResults(results, expected);
366 });
367
368 test('riskPercentiles.doesNotDivideByZeroWhenSumLessThanWhole', () => {
369 // Durations chosen such that, due to floating point error:
370 // var idleTime = totalTime - (duration1 + duration2);
371 // (idleTime + duration1 + duration2) < totalTime
372 // Note(dproy): Since we now supply the percentiles as ints instead of
charliea (OOO until 10-5) 2016/09/19 14:35:34 Please make this NOTE: and not Note(dproy). We usu
dproy 2016/09/20 01:11:43 This note is obselete because I changed percentile
373 // floats it's not clear if this test is still effective. If a divide by
374 // zero bug resurfaces, this test should be fixed.
375 var duration1 = 67 / 107;
376 var duration2 = 67 / 53;
377 var totalTime = 10;
378 var results = calculateEILRiskPercentiles(
379 [duration1, duration2], totalTime, [1], 0);
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: line continuations (here and elsewhere)
dproy 2016/09/20 01:11:44 Done (here and elsewhere)
380 var expected = duration2;
381 assert.closeTo(results.get(1), expected, FPTOLERANCE);
382 });
383
384 });
385 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698