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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: tracing/tracing/metrics/estimated_input_latency_metric_test.html
diff --git a/tracing/tracing/metrics/estimated_input_latency_metric_test.html b/tracing/tracing/metrics/estimated_input_latency_metric_test.html
new file mode 100644
index 0000000000000000000000000000000000000000..f9d2b400bc797ae670cd641b0f815f2cd94fedbe
--- /dev/null
+++ b/tracing/tracing/metrics/estimated_input_latency_metric_test.html
@@ -0,0 +1,385 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/metrics/estimated_input_latency_metric.html">
+<link rel="import" href="/tracing/metrics/system_health/loading_metric.html">
+<link rel="import" href="/tracing/value/value_set.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ 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.
+ var MAIN_THREAD_ID = 2;
+ var INTERACTIVE_WINDOW_SIZE_MS = tr.metrics.sh.INTERACTIVE_WINDOW_SIZE_MS;
+ var calculateEILRiskPercentiles = tr.metrics.calculateEILRiskPercentiles;
+
+ function newSchedulerTask(startTime, duration) {
+ return tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: 'TaskQueueManager::ProcessTaskFromWorkQueue',
+ start: startTime,
+ duration: duration
+ });
+ }
+
+ function assertTasksNotTooLong(tti, taskList) {
+ // 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
+ // responsiveness threshold because otherwise it will push back TTI.
+ // If we change RESPONSIVENESS_THRESHOLD_MS or INTERACTIVE_WINDOW_SIZE_MS in
+ // TTI we may have to change the task durations for this test.
+ for (var task of taskList) {
+ if (task.start < tti + INTERACTIVE_WINDOW_SIZE_MS) {
+ assert.isBelow(
+ 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.
+ }
+ }
+ }
+
+ function addTasksToThread(mainThread, tti, taskList) {
+ assertTasksNotTooLong(tti, taskList);
+ for (var task of taskList) {
+ mainThread.sliceGroup.pushSlice(
+ newSchedulerTask(task.start, task.duration));
+ }
+ }
+
+ function createTestModel(rendererCallback) {
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var rendererProcess = model.getOrCreateProcess(1);
+ var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
+ mainThread.name = 'CrRendererMain';
+ rendererCallback(rendererProcess);
+ });
+ return model;
+ }
+
+ function addTestFrame(rendererProcess) {
+ // We need FMP for TTI, and FMP needs to reference a frame.
+ rendererProcess.objects.addSnapshot(
+ '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.
+ {isLoadingMainFrame: true, frame: {id_ref: '0xdeadbeef'},
+ 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
+ }
+
+ function addInteractiveWindow(
+ 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.
+ // To get to TTI, we need a firstMeaningfulPaint and a sufficiently large
+ // window of no long tasks.
+ var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'blink.user_timing',
+ title: 'navigationStart',
+ start: startNavigationTime,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'loading',
+ title: 'firstMeaningfulPaintCandidate',
+ start: ttiTime,
+ duration: 0.0,
+ args: {frame: '0xdeadbeef'}
+ }));
+
+ // Add a 0 duration task at the end so we hit the required window size.
+ mainThread.sliceGroup.pushSlice(
+ 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.
+ }
+
+ function prepareModelForSingleWindowTest(tti, postTTITasks) {
+ var model = createTestModel(rendererProcess => {
+ var startNavTime = 0;
+ addTestFrame(rendererProcess);
+ addInteractiveWindow(rendererProcess, startNavTime, tti);
+ var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
+ addTasksToThread(mainThread, tti, postTTITasks);
+ });
+ return model;
+ }
+
+ function computeEQT90Numeric(model) {
+ var values = new tr.v.ValueSet();
+ tr.metrics.estimatedInputLatencyMetric(values, model);
+ var numeric = tr.b.getOnlyElement(values.getValuesNamed(
+ '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.
+ return numeric;
+ }
+
+ test('eqt90thPercentileTest40msFull', function() {
+ var tti = 1000;
+ var postTTITasks = [];
+ var taskDur = 40;
+ var windowEnd = tti + INTERACTIVE_WINDOW_SIZE_MS;
+ for (var startTime = tti; startTime < windowEnd; startTime += taskDur) {
+ 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
+ }
+
+ var model = prepareModelForSingleWindowTest(tti, postTTITasks);
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 1);
+ assert.closeTo(numeric.running.mean, 36, FPTOLERANCE);
+ });
+
+ test('eqt90thPercentileTestZeroEQT', function() {
+ var tti = 1000;
+ 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
+ var model = prepareModelForSingleWindowTest(tti, postTTITasks);
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 1);
+ assert.equal(numeric.running.mean, 0);
+ });
+
+ test('eqt90thPercentileTestLargePostTTITask', function() {
+ var tti = 1000;
+ var postTTITasks = [
+ {start: tti + INTERACTIVE_WINDOW_SIZE_MS, duration: 5000}
+ ];
+
+ var model = prepareModelForSingleWindowTest(tti, postTTITasks);
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 1);
+ assert.closeTo(numeric.running.mean, 4000, FPTOLERANCE);
+ });
+
+ test('eqt90thPercentileTestAlternate40ms', function() {
+ var tti = 1000;
+ var postTTITasks = [];
+ var taskDur = 40;
+ var windowEnd = tti + INTERACTIVE_WINDOW_SIZE_MS;
+ for (var startTime = tti; startTime < windowEnd; startTime += 2 * taskDur) {
+ postTTITasks.push({start: startTime, duration: taskDur});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: one line branch
+ }
+ var model = prepareModelForSingleWindowTest(tti, postTTITasks);
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 1);
+ assert.closeTo(numeric.running.mean, 32, FPTOLERANCE);
+ });
+
+ test('eqt90thPercentileMultipleWindows', function() {
+ // There are five interactive windows:
+ // window 1 - 3 have zero tasks
+ // window 4 is full of back to back 40 ms tasks
+ // window 5 has alternating 40ms task and 40ms idleTime
+
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.
+ var model = createTestModel(rendererProcess => {
+ addTestFrame(rendererProcess);
+ var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
+
+ for (var i = 0; i < 5; i++) {
+ var startNavigationTime = i * 10000;
+ var ttiTime = startNavigationTime + 1000;
+ var windowEnd = (i + 1) * 10000;
+ addInteractiveWindow(
+ rendererProcess, startNavigationTime, ttiTime, windowEnd);
+ }
+
+ var taskDur = 40;
+ var win4Tasks = [];
+ var win4Interactive = 31000;
+ var win4End = 40000;
+ for (var startTime = win4Interactive;
+ startTime < win4End; startTime += taskDur) {
+ win4Tasks.push({start: startTime, duration: taskDur});
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for braces
+ }
+ addTasksToThread(mainThread, win4Interactive, win4Tasks);
+
+ var win5Tasks = [];
+ var win5Interactive = 41000;
+ var win5End = 50000;
+ for (var startTime = win5Interactive;
+ startTime < win5End; startTime += 2 * taskDur) {
+ win5Tasks.push({start: startTime, duration: taskDur});
+ }
+ addTasksToThread(mainThread, win5Interactive, win5Tasks);
+ });
+
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 5);
+ numeric.sampleValues.slice(0, 3).forEach(v => assert.equal(v, 0));
+ assert.closeTo(numeric.sampleValues[3], 36, FPTOLERANCE);
+ assert.closeTo(numeric.sampleValues[4], 32, FPTOLERANCE);
+ });
+
+ test('properlyIterateSchedulerTasks', function() {
+ // Test that we handle both top level message loop tasks and nested renderer
+ // scheduler tasks. We add 2000ms worth of back to back 40ms
+ // MessageLoop::RunTask slices with no nested scheduler task, and then one
+ // big 3000ms MessageLoop::RunTask with 2000ms worth of back to back 40ms
+ // nested scheduler tasks inside.
+
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.
+ var messageLoopTaskTitle = 'MessageLoop::RunTask';
+ var schedulerTaskTitle = 'TaskQueueManager::ProcessTaskFromWorkQueue';
+ var model = createTestModel(rendererProcess => {
+ var startNavTime = 0;
+ var tti = 1000;
+ var taskDur = 40;
+ assert.isBelow(taskDur, tr.metrics.sh.RESPONSIVENESS_THRESHOLD_MS);
+
+ addTestFrame(rendererProcess);
+ addInteractiveWindow(rendererProcess, startNavTime, tti);
+ var mainThread = rendererProcess.getOrCreateThread(MAIN_THREAD_ID);
+
+ for (var start = tti; start < tti + 2000; start += taskDur) {
+ mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: messageLoopTaskTitle,
+ start: start,
+ duration: taskDur
+ }));
+ }
+
+ // A huge ML task with back to back 40ms tasks in scheduler
+ var giantMessageLoopSlice = tr.c.TestUtils.newSliceEx({
+ cat: 'toplevel',
+ title: messageLoopTaskTitle,
+ start: 3000,
+ duration: 3000
+ });
+
+ // back to back for 3000
+ var schedulerDoWork = tr.c.TestUtils.newSliceEx({
+ cat: 'not-toplevel',
+ title: 'TaskQueueManager::DoWork',
+ start: 3500,
+ duration: 2000
+ });
+
+ for (var start = 3500; start < 3500 + 2000; start += taskDur) {
+ schedulerDoWork.subSlices.push(newSchedulerTask(start, taskDur));
charliea (OOO until 10-5) 2016/09/19 14:35:34 nit: no need for braces
+ }
+
+ giantMessageLoopSlice.subSlices.push(schedulerDoWork);
+ mainThread.sliceGroup.pushSlice(giantMessageLoopSlice);
+ })
+
+ var numeric = computeEQT90Numeric(model);
+ assert.equal(numeric.running.count, 1);
+ assert.closeTo(numeric.running.mean, 30, FPTOLERANCE);
+ });
+
+
charliea (OOO until 10-5) 2016/09/19 14:35:33 nit: extra blank line
dproy 2016/09/20 01:11:43 Done.
+ // riskPercentiles tests ported from Lighthouse
+ var defaultPercentiles = [0, .25, .50, .75, .90, .99, 1];
+
+ function verifyAllResults(results, expected) {
+ for (var i = 0; i < defaultPercentiles.length; i++) {
+ var computedEqt = results.get(defaultPercentiles[i]);
+ var expectedEqt = expected[i];
+ console.log(results, expected, i);
+ assert.closeTo(computedEqt, expectedEqt, FPTOLERANCE);
+ }
+ }
+
+ test('riskPercentiles.PercentileOfNoTasks', () => {
+ var results = calculateEILRiskPercentiles([], 100, defaultPercentiles);
+ var expected = [0, 0, 0, 0, 0, 0, 0];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.singleTaskWithIdleTime', () => {
+ var results = calculateEILRiskPercentiles([50], 100, defaultPercentiles);
+ var expected = [0, 0, 0, 25, 40, 49, 50];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.singleTaskNoIdleTime', () => {
+ var results = calculateEILRiskPercentiles([50], 50, defaultPercentiles);
+ var expected = [0, 12.5, 25, 37.5, 45, 49.5, 50];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.severalEqualLengthTasks', () => {
+ var results = calculateEILRiskPercentiles(
+ [50, 50, 50, 50], 400, defaultPercentiles);
+ var expected = [0, 0, 0, 25, 40, 49, 50];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.zeroDurationTask', () => {
+ var results = calculateEILRiskPercentiles(
+ [0, 0, 0, 10, 20, 20, 30, 30, 120], 320, defaultPercentiles);
+ var expected = [0, 0, 12, 40, 88, 116.8, 120];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.threeOneSecondInFiveSecondWindow', () => {
+ // Three tasks of one second each, all within a five-second window.
+ // Mean Queueing Time of 300ms.
+ var results = calculateEILRiskPercentiles(
+ [1000, 1000, 1000], 5000, defaultPercentiles, 0);
+ var expected = [0, 0, 166.67, 583.33, 833.33, 983.33, 1000];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.clippedTask', () => {
+ var results = calculateEILRiskPercentiles(
+ [10, 20, 50, 60, 90, 100], 300, defaultPercentiles, 30);
+ var expected = [0, 16.25, 37.5, 58.33, 80, 97, 100];
+ verifyAllResults(results, expected);
+
+ });
+
+ test('riskPercentiles.singleTaskOverMultipleWindows', () => {
+ // One 20 second long task over three five-second windows.
+
+ // Starts 3 seconds into the first window. Mean Queueing Time = 7600ms.
+ var TASK_LENGTH = 20000;
+ let results1 = calculateEILRiskPercentiles(
+ [TASK_LENGTH], 5000, defaultPercentiles, TASK_LENGTH - 2000);
+ var expected1 = [0, 0, 0, 18750, 19500, 19950, 20000];
+ verifyAllResults(results1, expected1);
+
+ // Starts 2 seconds before and ends 13 seconds after.
+ // Mean Queueing Time = 15500ms.
+ var results2 = calculateEILRiskPercentiles(
+ [TASK_LENGTH - 2000], 5000, defaultPercentiles, TASK_LENGTH - 7000);
+ var expected2 = [0, 14250, 15500, 16750, 17500, 17950, 18000];
+ verifyAllResults(results2, expected2);
+
+ // Starts 17 seconds before and ends 3 seconds into the window.
+ // Mean Queueing Time = 900ms.
+ var results3 = calculateEILRiskPercentiles(
+ [TASK_LENGTH - 17000], 5000, defaultPercentiles, 0);
+ var expected3 = [0, 0, 500, 1750, 2500, 2950, 3000];
+ verifyAllResults(results3, expected3);
+ });
+
+ test('riskPercentiles.oneTaskShorterThanClippedLengthOfAnother', () => {
+ var results = calculateEILRiskPercentiles(
+ [40, 100], 100, defaultPercentiles, 50);
+ var expected = [0, 15, 40, 75, 90, 99, 100];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.completelyClippedTask', () => {
+ var results = calculateEILRiskPercentiles(
+ [40, 100], 100, defaultPercentiles, 100);
+ var expected = [0, 0, 0, 15, 30, 39, 40];
+ verifyAllResults(results, expected);
+ });
+
+ test('riskPercentiles.doesNotDivideByZeroWhenSumLessThanWhole', () => {
+ // Durations chosen such that, due to floating point error:
+ // var idleTime = totalTime - (duration1 + duration2);
+ // (idleTime + duration1 + duration2) < totalTime
+ // 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
+ // floats it's not clear if this test is still effective. If a divide by
+ // zero bug resurfaces, this test should be fixed.
+ var duration1 = 67 / 107;
+ var duration2 = 67 / 53;
+ var totalTime = 10;
+ var results = calculateEILRiskPercentiles(
+ [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)
+ var expected = duration2;
+ assert.closeTo(results.get(1), expected, FPTOLERANCE);
+ });
+
+});
+</script>

Powered by Google App Engine
This is Rietveld 408576698