Chromium Code Reviews| 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 |