blob: 8c2ac10f485715436f1bf3c8bb76cc136c814bb1 [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/android_startup_metric.html">
<link rel="import" href="/tracing/value/histogram_set.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
function createBrowserThread(model) {
const browserProcess = model.getOrCreateProcess(tr.b.GUID.allocateSimple());
const mainThread = browserProcess.getOrCreateThread(
tr.b.GUID.allocateSimple());
// Initializing the thread name helps passing validation checks made by the
// ChromeModelHelper.
mainThread.name = 'CrBrowserMain';
return mainThread;
}
function createRendererThread(model) {
const rendererProcess = model.getOrCreateProcess(
tr.b.GUID.allocateSimple());
const rendererMainThread =
rendererProcess.getOrCreateThread(tr.b.GUID.allocateSimple());
rendererMainThread.name = 'CrRendererMain';
return rendererMainThread;
}
// Adds a browser and renderer to the process, with a few key events necessary
// to calculate the |androidStartupMetric|. An |offset| can be added to all
// events and the length of a few events can be extended by
// |incrementForMetrics|.
function fillModelWithOneBrowserSession(model, offset, incrementForMetrics) {
// In order for the tests below to succeed with strictEqual, the floating
// point values should have exact representation as IEEE754 float.
const browserMainThread = createBrowserThread(model);
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.LoadTime.ProcessCreateToApplicationStart',
start: (offset + 5000),
duration: (incrementForMetrics + 100)}));
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.BrowserMessageLoopStartTime',
start: (offset + 6800.125),
duration: (incrementForMetrics + 1700.0625)}));
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'navigation',
title: 'Navigation StartToCommit',
start: (offset + 9000.5 + incrementForMetrics),
duration: (incrementForMetrics + 2000.5)}));
const rendererMainThread = createRendererThread(model);
rendererMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'startup',
title: 'content::Start',
start: (offset + 9500.125 + incrementForMetrics),
duration: 10000.0}));
rendererMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: (offset + 8400.125 + incrementForMetrics),
duration: 0.0,
args: {frame: '0x0'}}));
// Add an extra FCP event in the same renderer process appearing after the
// initial FCP even to check that it is ignored by metric computations.
rendererMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: (offset + 8400.125 + incrementForMetrics + 0.125),
duration: 0.0,
args: {frame: '0x0'}}));
}
// Adds early messageloop and FCP events. The metric should ignore these very
// first messageloop start and FCP events in the trace. The specific lengths
// are not important.
function addEarlyEventsToBeIgnored(model, offset) {
const browserMainThread = createBrowserThread(model);
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.LoadTime.ProcessCreateToApplicationStart',
start: offset,
duration: 1.0}));
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.BrowserMessageLoopStartTime',
start: (offset + 1.0),
duration: 10.0}));
const rendererMainThread = createRendererThread(model);
rendererMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: (offset + 2.0),
duration: 1.0,
args: {frame: '0x0'}}));
}
function makeTestModel(offset, incrementForMetrics) {
return tr.c.TestUtils.newModel(function(model) {
fillModelWithOneBrowserSession(model, offset, incrementForMetrics);
addEarlyEventsToBeIgnored(model, offset);
addEarlyEventsToBeIgnored(model, offset + 20.0);
});
}
function verifyHistogram(histograms, name, numValues, average) {
const histogram = histograms.getHistogramNamed(name);
assert.strictEqual(numValues, histogram.numValues);
assert.strictEqual(average, histogram.average);
}
function verifyHistogramRange(histograms, name, numValues, min, max) {
const histogram = histograms.getHistogramNamed(name);
assert.strictEqual(numValues, histogram.numValues);
assert.strictEqual(min, histogram.min);
assert.strictEqual(max, histogram.max);
}
// Checks recording of the main histograms in the simplest case.
test('androidStartupMetric_simple', function() {
const histograms = new tr.v.HistogramSet();
tr.metrics.sh.androidStartupMetric(histograms, makeTestModel(0.0, 0.0));
verifyHistogram(histograms, 'messageloop_start_time', 1, 1700.0625);
verifyHistogram(histograms, 'experimental_navigation_start_time', 1,
2200.375);
verifyHistogram(histograms, 'navigation_commit_time', 1, 4200.875);
verifyHistogram(histograms, 'experimental_content_start_time', 1, 2700);
verifyHistogram(histograms, 'first_contentful_paint_time', 1, 1600);
verifyHistogram(histograms, 'process_create_to_app_start_time', 1, 100);
});
// Emulates loss of the initial message loop start event. Checks that this
// event is ignored and the |androidStartupMetric| does not crash.
test('androidStartupMetric_missingOneBrowserStart', function() {
function makeTestModelWithOneEventMissing() {
return tr.c.TestUtils.newModel(function(model) {
fillModelWithOneBrowserSession(model, 0.0, 0.0);
// Note: the initial Startup.BrowserMessageLoopStartTime'
// is intentionally missing.
createRendererThread(model).sliceGroup.pushSlice(
tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: 2.0,
duration: 1.0,
args: {frame: '0x0'}}));
const browserMainThread = createBrowserThread(model);
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.BrowserMessageLoopStartTime',
start: (20.0 + 1.0),
duration: 10.0}));
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'navigation',
title: 'Navigation StartToCommit',
start: (20.0 + 11.0),
duration: 10.0}));
const rendererMainThread = createRendererThread(model);
rendererMainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
cat: 'startup',
title: 'content::Start',
start: (20.0 + 1.75),
duration: 10.0}));
rendererMainThread.sliceGroup.pushSlice(
tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: (20.0 + 2.0),
duration: 1.0,
args: {frame: '0x0'}}));
});
}
const histograms = new tr.v.HistogramSet();
tr.metrics.sh.androidStartupMetric(histograms,
makeTestModelWithOneEventMissing(0.0));
verifyHistogram(histograms, 'messageloop_start_time', 1, 1700.0625);
verifyHistogram(histograms, 'experimental_navigation_start_time', 1,
2200.375);
verifyHistogram(histograms, 'navigation_commit_time', 1, 4200.875);
verifyHistogram(histograms, 'experimental_content_start_time', 1, 2700);
verifyHistogram(histograms, 'first_contentful_paint_time', 1, 1600);
});
test('androidStartupMetric_missingExperimentalEvents', function() {
function makeTestModelWithMissingExperimentalEvents() {
return tr.c.TestUtils.newModel(function(model) {
const browserMainThread = createBrowserThread(model);
browserMainThread.asyncSliceGroup.push(
tr.c.TestUtils.newAsyncSliceEx({
cat: 'startup',
title: 'Startup.BrowserMessageLoopStartTime',
start: (20.0 + 1.0),
duration: 10.0}));
const rendererMainThread = createRendererThread(model);
rendererMainThread.sliceGroup.pushSlice(
tr.c.TestUtils.newSliceEx({
cat: 'loading,rail,devtools.timeline',
title: 'firstContentfulPaint',
start: (20.0 + 2.0),
duration: 1.0,
args: {frame: '0x0'}}));
addEarlyEventsToBeIgnored(model, 0.0, 0.0);
addEarlyEventsToBeIgnored(model, 10.0);
});
}
const histograms = new tr.v.HistogramSet();
tr.metrics.sh.androidStartupMetric(histograms,
makeTestModelWithMissingExperimentalEvents());
verifyHistogram(histograms, 'messageloop_start_time', 1, 10);
verifyHistogram(histograms, 'experimental_navigation_start_time', 0,
undefined);
verifyHistogram(histograms, 'navigation_commit_time', 0, undefined);
verifyHistogram(histograms, 'experimental_content_start_time', 0,
undefined);
verifyHistogram(histograms, 'first_contentful_paint_time', 1, 2);
verifyHistogram(histograms, 'process_create_to_app_start_time', 0,
undefined);
});
// Checks the metrics after adding an offset to events in the model, and
// making a few durations longer by a constant.
test('androidStartupMetric_withOffsetAndLongerTask', function() {
const histograms = new tr.v.HistogramSet();
tr.metrics.sh.androidStartupMetric(histograms, makeTestModel(5.0, 7.0));
verifyHistogram(histograms, 'messageloop_start_time', 1, 1707.0625);
verifyHistogram(histograms, 'experimental_navigation_start_time', 1,
2207.375);
verifyHistogram(histograms, 'navigation_commit_time', 1, 4214.875);
verifyHistogram(histograms, 'experimental_content_start_time', 1, 2707);
verifyHistogram(histograms, 'first_contentful_paint_time', 1, 1607);
verifyHistogram(histograms, 'process_create_to_app_start_time', 1, 107);
});
test('androidStartupMetric_twoSessions', function() {
function makeTestModelWithTwoSessionsOneDelayed(
offset, incrementForMetrics) {
return tr.c.TestUtils.newModel(function(model) {
fillModelWithOneBrowserSession(model, 0.0, 0.0);
fillModelWithOneBrowserSession(model, offset, incrementForMetrics);
addEarlyEventsToBeIgnored(model, 0.0, 0.0);
addEarlyEventsToBeIgnored(model, 0.0, 1.0);
});
}
const delta = 0.125;
const histograms = new tr.v.HistogramSet();
tr.metrics.sh.androidStartupMetric(histograms,
makeTestModelWithTwoSessionsOneDelayed(10000.0, delta));
verifyHistogramRange(histograms, 'messageloop_start_time',
2, 1700.0625, 1700.0625 + delta);
verifyHistogramRange(histograms, 'experimental_navigation_start_time',
2, 2200.375, 2200.375 + delta);
verifyHistogramRange(histograms, 'navigation_commit_time',
2, 4200.875, 4200.875 + delta * 2);
verifyHistogramRange(histograms, 'experimental_content_start_time',
2, 2700, 2700 + delta);
verifyHistogramRange(histograms, 'first_contentful_paint_time',
2, 1600, 1600 + delta);
verifyHistogramRange(histograms, 'process_create_to_app_start_time', 2, 100,
100 + delta);
});
});
</script>