blob: 44c38038d3b59d82dd2afde214db38dbec3d59ff [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright 2017 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/spa_navigation_metric.html">
<link rel="import" href="/tracing/value/histogram_set.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
const RENDERER_PROCESS_ID = 1234;
const RENDERER_PROCESS_MAIN_THREAD_ID = 1;
const BROWSER_PROCESS_ID = 1;
const BROWSER_PROCESS_MAIN_THREAD_ID = 12;
const SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION =
'spaNavigationStartToFpDuration';
function createChromeProcessesOnModel(model) {
const rendererProcess = model.getOrCreateProcess(RENDERER_PROCESS_ID);
const mainThread = rendererProcess.getOrCreateThread(
RENDERER_PROCESS_MAIN_THREAD_ID);
mainThread.name = 'CrRendererMain';
const browserProcess = model.getOrCreateProcess(BROWSER_PROCESS_ID);
const browserMainThread = browserProcess.getOrCreateThread(
BROWSER_PROCESS_MAIN_THREAD_ID);
browserMainThread.name = 'CrBrowserMain';
}
function addSpaNavigationEvent(model, timestamp, args) {
const rendererProcess = model.getOrCreateProcess(RENDERER_PROCESS_ID);
const mainThread = rendererProcess.getOrCreateThread(
RENDERER_PROCESS_MAIN_THREAD_ID);
mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'blink',
title: 'FrameLoader::updateForSameDocumentNavigation',
start: timestamp,
duration: 0.1,
args
}));
}
function addGoToIndexSlice(model, timestamp) {
const browserProcess = model.getOrCreateProcess(BROWSER_PROCESS_ID);
const browserMainThread = browserProcess.getOrCreateThread(
BROWSER_PROCESS_MAIN_THREAD_ID);
browserMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'browser,navigation,benchmark',
title: 'NavigationControllerImpl::GoToIndex',
start: timestamp,
duration: 0.1
}));
}
function addFirstPaintSlice(model, timestamp) {
const rendererProcess = model.getOrCreateProcess(RENDERER_PROCESS_ID);
const mainThread = rendererProcess.getOrCreateThread(
RENDERER_PROCESS_MAIN_THREAD_ID);
mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'blink',
title: 'PaintLayerCompositor::updateIfNeededRecursive',
start: timestamp,
duration: 0.1
}));
}
function addInputLatencyRelatedSlices(model, timestamp) {
const latencyInfoFlowSlice = tr.c.TestUtils.newSliceEx({
cat: 'input,benchmark',
title: 'LatencyInfo.Flow',
start: timestamp - 2,
duration: 0.1,
bindId: '0x600000057',
args: {step: 'handleInputEventMain'}
});
const handleInputEventSlice = tr.c.TestUtils.newSliceEx({
cat: 'blink,rail',
title: 'WebViewImpl::handleInputEvent',
start: timestamp - 1, // Assume handleInputEvent always delays 1ms.
duration: 0.1,
args: {type: 'MouseUp'}
});
const rendererProcess = model.getOrCreateProcess(RENDERER_PROCESS_ID);
const mainThread = rendererProcess.getOrCreateThread(
RENDERER_PROCESS_MAIN_THREAD_ID);
handleInputEventSlice.parentSlice = latencyInfoFlowSlice;
mainThread.sliceGroup.pushSlice(latencyInfoFlowSlice);
mainThread.sliceGroup.pushSlice(handleInputEventSlice);
const browserProcess = model.getOrCreateProcess(BROWSER_PROCESS_ID);
const browserMainThread = browserProcess.getOrCreateThread(
BROWSER_PROCESS_MAIN_THREAD_ID);
browserMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newAsyncSliceEx({
cat: 'benchmark,latencyInfo,rail',
title: 'InputLatency::MouseUp',
start: timestamp - 3,
duration: 0.1,
args: {
data: {
trace_id: 25769803863,
INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT: {
time: timestamp - 3 + 0.1
}
}
}
}));
}
function getHistogramNamed(name, model) {
const histograms = new tr.v.HistogramSet();
tr.metrics.spaNavigationMetric(histograms, model);
const spaNavigationStartToFpDurationHist = histograms.getHistogramNamed(
name);
return spaNavigationStartToFpDurationHist;
}
test('spaNavStartToFirstPaintDuration_noChromeProcess', function() {
const model = tr.c.TestUtils.newModel();
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert(!histogram);
});
test('spaNavStartToFirstPaintDuration_noSpaNavStart', function() {
const model = tr.c.TestUtils.newModel(model => {
createChromeProcessesOnModel(model);
addSpaNavigationEvent(model, 100);
addFirstPaintSlice(model, 101);
});
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert.strictEqual(0, histogram.numValues);
});
test('spaNavStartToFirstPaintDuration_noFirstPaint', function() {
const model = tr.c.TestUtils.newModel(model => {
createChromeProcessesOnModel(model);
addInputLatencyRelatedSlices(model, 99);
addSpaNavigationEvent(model, 100);
});
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert.strictEqual(0, histogram.numValues);
});
test('spaNavStartToFirstPaintDuration_inputLatencyAsNavStart', function() {
const URL = 'https://11111';
const model = tr.c.TestUtils.newModel(model => {
createChromeProcessesOnModel(model);
addInputLatencyRelatedSlices(model, 99);
addSpaNavigationEvent(model, 100, {url: URL});
addFirstPaintSlice(model, 101);
});
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert.strictEqual(1, histogram.running.count);
const navStartTs = model.convertTimestampToModelTime(
'traceEventClock', 99 - 3 + 0.1);
const expectedDuration = 101 - navStartTs;
assert.closeTo(expectedDuration, histogram.running.sum, 0.5);
const binsWithSampleDiagnosticMaps =
histogram.allBins.filter(bin => bin.diagnosticMaps.length > 0);
const diagnostic = tr.b.getOnlyElement(binsWithSampleDiagnosticMaps[0]
.diagnosticMaps[0].get('Navigation infos'));
assert.strictEqual(diagnostic.url, URL);
assert.strictEqual(diagnostic.pid, RENDERER_PROCESS_ID);
assert.strictEqual(diagnostic.navStart, navStartTs);
assert.strictEqual(diagnostic.firstPaint, 101);
});
test('spaNavStartToFirstPaintDuration_goToIndexAsNavStart', function() {
const URL = 'https://11111';
const model = tr.c.TestUtils.newModel(model => {
createChromeProcessesOnModel(model);
addGoToIndexSlice(model, 99);
addSpaNavigationEvent(model, 100, {url: URL});
addFirstPaintSlice(model, 101);
});
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert.strictEqual(1, histogram.running.count);
const expectedDuration = 101 - 99;
assert.closeTo(expectedDuration, histogram.running.sum, 0.5);
const binsWithSampleDiagnosticMaps =
histogram.allBins.filter(bin => bin.diagnosticMaps.length > 0);
const diagnostic = tr.b.getOnlyElement(binsWithSampleDiagnosticMaps[0]
.diagnosticMaps[0].get('Navigation infos'));
assert.strictEqual(diagnostic.url, URL);
assert.strictEqual(diagnostic.pid, RENDERER_PROCESS_ID);
assert.strictEqual(diagnostic.navStart, 99);
assert.strictEqual(diagnostic.firstPaint, 101);
});
test('spaNavStartToFirstPaintDuration_multipleSpaNavs', function() {
const model = tr.c.TestUtils.newModel(model => {
createChromeProcessesOnModel(model);
addInputLatencyRelatedSlices(model, 99);
addSpaNavigationEvent(model, 100);
addFirstPaintSlice(model, 101);
addInputLatencyRelatedSlices(model, 198);
addSpaNavigationEvent(model, 200);
addFirstPaintSlice(model, 201);
addInputLatencyRelatedSlices(model, 297);
addSpaNavigationEvent(model, 300);
addFirstPaintSlice(model, 301);
});
const histogram = getHistogramNamed(
SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION, model);
assert.strictEqual(3, histogram.running.count);
const expectedDuration1 = 101 - model.convertTimestampToModelTime(
'traceEventClock', 99 - 3 + 0.1);
const expectedDuration2 = 201 - model.convertTimestampToModelTime(
'traceEventClock', 198 - 3 + 0.1);
const expectedDuration3 = 301 - model.convertTimestampToModelTime(
'traceEventClock', 297 - 3 + 0.1);
assert.closeTo(expectedDuration1 + expectedDuration2 + expectedDuration3,
histogram.running.sum, 0.5);
assert.closeTo(expectedDuration3, histogram.running.max, 0.5);
assert.closeTo(expectedDuration1, histogram.running.min, 0.5);
});
});
</script>