| <!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/speed_index_utils.html"> |
| <link rel="import" href="/tracing/metrics/system_health/breakdown_tree_helpers.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.metrics.sh', function() { |
| const timeDurationInMs_smallerIsBetter = |
| tr.b.Unit.byName.timeDurationInMs_smallerIsBetter; |
| const SpeedIndex = tr.e.chrome.SpeedIndex; |
| const EventFinderUtils = tr.e.chrome.EventFinderUtils; |
| |
| const BIN_BOUNDARIES = tr.v.HistogramBinBoundaries |
| .createLinear(0, 1e3, 20) // 50ms step to 1s |
| .addLinearBins(3e3, 20) // 100ms step to 3s |
| .addExponentialBins(20e3, 20); |
| |
| |
| const SUMMARY_OPTIONS = { |
| avg: true, |
| count: false, |
| max: true, |
| min: true, |
| std: true, |
| sum: false, |
| }; |
| |
| /** |
| * Adds a speed index sample. |
| * |
| * @param {tr.model.helpers.ChromeBrowserrHelper} browserHelper |
| * @param {number[]} samples |
| * @param {tr.model.ThreadSlice} navigationStart |
| */ |
| function addRectsBasedSpeedIndexSample(samples, rendererHelper, |
| navigationStart, loadDuration, frameID) { |
| let viewport; |
| // We're looking for the last viewport recorded before end of loading. |
| for (const event of EventFinderUtils.getMainThreadEvents(rendererHelper, |
| 'viewport', 'loading')) { |
| if (event.args.data.frameID === frameID && |
| event.start < (navigationStart + loadDuration)) { |
| viewport = event.args.data; |
| } |
| } |
| if (!viewport) return; |
| |
| const timestampedPaintRects = []; |
| for (const event of EventFinderUtils.getMainThreadEvents(rendererHelper, |
| 'PaintTimingVisualizer::LayoutObjectPainted', 'loading')) { |
| if (event.start >= navigationStart && |
| event.start < navigationStart + loadDuration) { |
| const paintRect = event.args.data.rect; |
| if (!paintRect) continue; |
| timestampedPaintRects.push({ |
| rect: SpeedIndex.quadToRect(paintRect), |
| ts: event.start}); |
| } |
| } |
| const numberOfRects = timestampedPaintRects.length; |
| if (numberOfRects === 0) return; |
| |
| samples.push({ |
| value: SpeedIndex.calculateRectsBasedSpeedIndex(timestampedPaintRects, |
| viewport) - navigationStart |
| }); |
| } |
| |
| function collectRectsBasedSpeedIndexSamplesFromLoadExpectations(model, |
| chromeHelper) { |
| const rectsBasedSpeedIndexSamples = []; |
| for (const expectation of model.userModel.expectations) { |
| if (!(expectation instanceof tr.model.um.LoadExpectation)) continue; |
| if (tr.e.chrome.CHROME_INTERNAL_URLS.includes(expectation.url)) { |
| continue; |
| } |
| const rendererHelper = chromeHelper.rendererHelpers[ |
| expectation.renderProcess.pid]; |
| addRectsBasedSpeedIndexSample(rectsBasedSpeedIndexSamples, rendererHelper, |
| expectation.navigationStart.start, expectation.duration, |
| expectation.navigationStart.args.frame); |
| } |
| return rectsBasedSpeedIndexSamples; |
| } |
| |
| function rectsBasedSpeedIndexMetric(histograms, model) { |
| const rectsBasedSpeedIndexHistogram = histograms.createHistogram( |
| 'rectsBasedSpeedIndex', timeDurationInMs_smallerIsBetter, [], { |
| binBoundaries: BIN_BOUNDARIES, |
| description: ' the average time at which visible parts of the' + |
| ' page are displayed (in ms).', |
| summaryOptions: SUMMARY_OPTIONS, |
| }); |
| |
| const chromeHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper); |
| |
| const samples = collectRectsBasedSpeedIndexSamplesFromLoadExpectations( |
| model, chromeHelper); |
| for (const sample of samples) { |
| rectsBasedSpeedIndexHistogram.addSample(sample.value); |
| } |
| } |
| |
| tr.metrics.MetricRegistry.register(rectsBasedSpeedIndexMetric); |
| |
| return { |
| rectsBasedSpeedIndexMetric |
| }; |
| }); |
| </script> |