blob: a4d35843630928f59f0f949c143719e55c34d05e [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright 2019 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/extras/chrome/event_finder_utils.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics', function() {
const timeDurationInMs_smallerIsBetter =
tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
const unitlessNumber_smallerIsBetter =
tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
const EventFinderUtils = tr.e.chrome.EventFinderUtils;
const METRIC_BOUNDARIES = tr.v.HistogramBinBoundaries
.createLinear(0, 1e3, 20) // 50ms step to 1s
.addLinearBins(3e3, 20) // 100ms step to 3s
.addExponentialBins(80e3, 30);
const SUMMARY_OPTIONS = {
avg: true,
count: false,
max: true,
min: true,
std: true,
sum: false,
};
/**
* Computes the following results
* - reported_by_page:time_to_viewable,
* - reported_by_page:time_to_interactive,
* - reported_by_page:benchmark_time.
*
* The metric is intended for pages that call
* - performance.mark(telemetry:reported_by_page:viewable),
* when the page showed meaningful content to the user.
* - performance.mark(telemetry:reported_by_page:interactive)
* when the page is ready to interact with the user.
* - performance.mark(telemetry:reported_by_page:benchmark_begin)
* when an important operation starts.
* - performance.mark(telemetry:reported_by_page:benchmark_end)
* when the important operation ends.
*/
function reportedByPageMetric(histograms, model) {
const timeToViewable = histograms.createHistogram(
'reported_by_page:time_to_viewable',
timeDurationInMs_smallerIsBetter, [], {
binBoundaries: METRIC_BOUNDARIES,
description: 'Time from navigation start' +
'to telemetry:reported_by_page:viewable',
summaryOptions: SUMMARY_OPTIONS,
});
const timeToInteractive = histograms.createHistogram(
'reported_by_page:time_to_interactive',
timeDurationInMs_smallerIsBetter, [], {
binBoundaries: METRIC_BOUNDARIES,
description: 'Time from navigation start ' +
'to telemetry:reported_by_page:interactive',
summaryOptions: SUMMARY_OPTIONS,
});
const benchmarkTime = histograms.createHistogram(
'reported_by_page:benchmark_time',
timeDurationInMs_smallerIsBetter, [], {
binBoundaries: METRIC_BOUNDARIES,
description:
'Time from telemetry:reported_by_page:benchmark_begin ' +
'to telemetry:reported_by_page:benchmark_end',
summaryOptions: SUMMARY_OPTIONS,
});
const chromeHelper = model.getOrCreateHelper(
tr.model.helpers.ChromeModelHelper);
for (const pid in chromeHelper.rendererHelpers) {
const rendererHelper = chromeHelper.rendererHelpers[pid];
if (rendererHelper.isChromeTracingUI) continue;
// Main thread may be missing. See crbug.com/1059726 for an example.
if (rendererHelper.mainThread === undefined) continue;
measureUserTime(rendererHelper,
'navigationStart',
'telemetry:reported_by_page:viewable',
timeToViewable);
measureUserTime(rendererHelper,
'navigationStart',
'telemetry:reported_by_page:interactive',
timeToInteractive);
measureUserTime(rendererHelper,
'telemetry:reported_by_page:benchmark_begin',
'telemetry:reported_by_page:benchmark_end',
benchmarkTime);
}
}
/*
* Finds all |startName|,|endName| event pairs that have the matching
* navigation ids on the main thread of the given renderer process
* and adds the duration from the start event to the end event to the
* given |histogram|.
*/
function measureUserTime(rendererHelper, startName, endName, histogram) {
// Maps navigation ids to the start events.
const startEventByNavId = new Map();
// Iterate events in the sorted order.
for (const event of rendererHelper.mainThread.sliceGroup.childEvents()) {
const navId = getNavigationId(event);
if (!navId) continue;
if (EventFinderUtils.hasCategoryAndName(
event, 'blink.user_timing', startName)) {
// Found a start event, save it.
startEventByNavId.set(navId, event);
}
if (EventFinderUtils.hasCategoryAndName(
event, 'blink.user_timing', endName)) {
if (!startEventByNavId.has(navId)) {
throw Error(`Missing ${startName} for ${endName} at {event.start}`);
}
// Found an end event. Compute the time from the previous start event.
const range = tr.b.math.Range.fromExplicitRange(
startEventByNavId.get(navId).start, event.start);
histogram.addSample(range.duration);
startEventByNavId.delete(navId);
}
}
}
function getNavigationId(event) {
return event.args.data && event.args.data.navigationId;
}
tr.metrics.MetricRegistry.register(reportedByPageMetric);
return {
reportedByPageMetric
};
});
</script>