| <!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/base/math/range.html"> |
| <link rel="import" href="/tracing/metrics/metric_registry.html"> |
| <link rel="import" href="/tracing/metrics/spa_navigation_helper.html"> |
| <link rel="import" href="/tracing/value/histogram.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.metrics', function() { |
| const SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION_BIN_BOUNDARY = |
| tr.v.HistogramBinBoundaries.createExponential(1, 1000, 50); |
| |
| /** |
| * This metric measures the duration between the input event |
| * causing a SPA navigation and the first paint event after it. |
| */ |
| function spaNavigationMetric(histograms, model) { |
| let histogram = new tr.v.Histogram( |
| 'spaNavigationStartToFpDuration', |
| tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, |
| SPA_NAVIGATION_START_TO_FIRST_PAINT_DURATION_BIN_BOUNDARY); |
| histogram.description = 'Latency between the input event causing' + |
| ' a SPA navigation and the first paint event after it'; |
| histogram.customizeSummaryOptions({ |
| count: false, |
| sum: false, |
| }); |
| |
| let modelHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper); |
| if (!modelHelper) { |
| // Chrome isn't present. |
| return; |
| } |
| let rendererHelpers = modelHelper.rendererHelpers; |
| if (!rendererHelpers) { |
| // We couldn't find any renderer processes. |
| return; |
| } |
| let browserHelper = modelHelper.browserHelper; |
| for (let rendererHelper of Object.values(rendererHelpers)) { |
| let spaNavigations = tr.metrics.findSpaNavigationsOnRenderer( |
| rendererHelper, browserHelper); |
| for (let spaNav of spaNavigations) { |
| let beginData = spaNav.navigationStart.args.data; |
| // TODO(sunjian): rename convertTimestampToModelTime to something like |
| // convertTraceEventTsToModelTs and get rid of the first parameter. |
| let beginTs = model.convertTimestampToModelTime( |
| 'traceEventClock', |
| beginData.INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT.time); |
| let duration = spaNav.firstPaintEvent.start - beginTs; |
| let breakdownDict = rendererHelper.generateWallClockTimeBreakdownTree( |
| beginTs, spaNav.firstPaintEvent.start); |
| let breakdownDiagnostic = new tr.v.d.Breakdown(); |
| breakdownDiagnostic.colorScheme = |
| tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER; |
| for (let label in breakdownDict) { |
| breakdownDiagnostic.set(label, |
| parseInt(breakdownDict[label].total * 1e3) / 1e3); |
| } |
| histogram.addSample( |
| duration, |
| { |
| 'Breakdown of [navStart, firstPaint]': breakdownDiagnostic, |
| 'Start': new tr.v.d.RelatedEventSet(spaNav.navigationStart), |
| 'End': new tr.v.d.RelatedEventSet(spaNav.firstPaintEvent), |
| 'Navigation infos': new tr.v.d.Generic({ |
| url: spaNav.url, |
| pid: rendererHelper.pid, |
| navStart: beginTs, |
| firstPaint: spaNav.firstPaintEvent.start |
| }) |
| }); |
| } |
| } |
| histograms.addHistogram(histogram); |
| } |
| |
| tr.metrics.MetricRegistry.register(spaNavigationMetric); |
| |
| return { |
| spaNavigationMetric, |
| }; |
| }); |
| </script> |