OLD | NEW |
---|---|
(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> | |
OLD | NEW |