Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Unified Diff: tracing/tracing/metrics/system_health/first_paint_metric.html

Issue 1963583005: Rewrite firstPaintMetric to support extracting multiple navigations from a single trace (Closed) Base URL: https://chromium.googlesource.com/external/github.com/catapult-project/catapult.git@master
Patch Set: rebased Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tracing/tracing/metrics/system_health/first_paint_metric_test.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tracing/tracing/metrics/system_health/first_paint_metric.html
diff --git a/tracing/tracing/metrics/system_health/first_paint_metric.html b/tracing/tracing/metrics/system_health/first_paint_metric.html
index f4cb399cc63bfa8501ad87b2997635e8ed2c83a7..d3e154929496d15e51b0e50b4e4953b8689f74d4 100644
--- a/tracing/tracing/metrics/system_health/first_paint_metric.html
+++ b/tracing/tracing/metrics/system_health/first_paint_metric.html
@@ -9,6 +9,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/system_health/utils.html">
<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
+<link rel="import" href="/tracing/model/timed_event.html">
<link rel="import" href="/tracing/value/numeric.html">
<link rel="import" href="/tracing/value/value.html">
@@ -19,10 +20,7 @@ tr.exportTo('tr.metrics.sh', function() {
var timeDurationInMs_smallerIsBetter =
tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;
- function findTargetRendererHelper(model) {
- var chromeHelper = model.getOrCreateHelper(
- tr.model.helpers.ChromeModelHelper);
-
+ function findTargetRendererHelper(chromeHelper) {
var largestPid = -1;
for (var pid in chromeHelper.rendererHelpers) {
var rendererHelper = chromeHelper.rendererHelpers[pid];
@@ -38,63 +36,155 @@ tr.exportTo('tr.metrics.sh', function() {
return chromeHelper.rendererHelpers[largestPid];
}
- function findNavigationStartEvent(rendererHelper) {
- var navigationStartEvent = undefined;
-
+ function navigationStartFinder(rendererHelper) {
+ var navigationStartsForFrameId = {};
rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer(
() => true, function(ev) {
- if (navigationStartEvent !== undefined ||
- ev.category !== 'blink.user_timing')
+ if (ev.category !== 'blink.user_timing' ||
+ ev.title !== 'navigationStart')
return;
- if (ev.title === 'navigationStart')
- navigationStartEvent = ev;
+
+ var frameIdRef = ev.args['frame'];
+ var list = navigationStartsForFrameId[frameIdRef];
+ if (list === undefined) {
+ navigationStartsForFrameId[frameIdRef] = list = [];
+ }
+ list.unshift(ev);
},
this);
- return navigationStartEvent;
+ return function findNavigationStartEventForFrameBeforeTimestamp(frameIdRef,
+ ts) {
+ var list = navigationStartsForFrameId[frameIdRef];
+ if (list === undefined)
+ throw new Error('No navigationStartEvent found for frame id "' +
+ frameIdRef + '"');
+
+ var eventBeforeTimestamp;
+ list.forEach(function(ev) {
+ if (ev.start > ts)
+ return;
+
+ if (eventBeforeTimestamp === undefined)
+ eventBeforeTimestamp = ev;
+ }, this);
+ if (eventBeforeTimestamp === undefined)
+ throw new Error('Failed to find navigationStartEvent.');
+ return eventBeforeTimestamp;
+ }
}
- function findFirstPaintEvent(rendererHelper, title, frame) {
- var firstPaintEvent = undefined;
+ function findUrlOfFrameAt(rendererHelper, frameIdRef, ts) {
+ var url;
+
+ var objects = rendererHelper.process.objects;
+ var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader'];
+ if (frameLoaderInstances === undefined) {
+ throw new Error(
+ 'Couldn\'t find any FrameLoader instances to query frame url.');
+ }
+ frameLoaderInstances.forEach(function(instance) {
+ if (!instance.isAliveAt(ts))
+ return;
+ var snapshot = instance.getSnapshotAt(ts);
+ if (frameIdRef !== snapshot.args['frame']['id_ref'])
+ return;
+
+ url = snapshot.args['documentLoaderURL'];
+ }, this);
+
+ return url;
+ }
+
+ function findFirstPaintEvents(rendererHelper, title) {
+ var firstPaintEvents = [];
rendererHelper.process.iterateAllEvents(
function(ev) {
- if (firstPaintEvent !== undefined ||
- ev.category !== 'blink.user_timing' ||
- ev.title !== title ||
- ev.args === undefined || ev.args['frame'] !== frame)
+ if (ev.category !== 'blink.user_timing' ||
+ ev.title !== title)
return;
- firstPaintEvent = ev;
+ firstPaintEvents.push(ev);
}, this);
- return firstPaintEvent;
+ return firstPaintEvents;
}
- function firstPaintMetric(values, model) {
- var rendererHelper = findTargetRendererHelper(model);
- var navigationStartEvent = findNavigationStartEvent(rendererHelper);
+ function prepareTelemetryInternalEventPredicate(rendererHelper) {
+ var ignoreRegions = [];
- if (navigationStartEvent === undefined)
- throw new Error('Failed to find navigationStartEvent.');
+ var warmCacheStart;
+ rendererHelper.mainThread.asyncSliceGroup.iterateAllEventsInThisContainer(
+ () => true, function(slice) {
+ if (slice.title === 'telemetry.internal.warmCache.start')
+ warmCacheStart = slice.start;
+ if (slice.title === 'telemetry.internal.warmCache.end') {
+ var warmCacheTimedEvent = new tr.model.TimedEvent(warmCacheStart);
+ warmCacheTimedEvent.duration = slice.end - warmCacheStart;
- var frame = navigationStartEvent.args['frame'];
- var firstContentfulPaintEvent = findFirstPaintEvent(rendererHelper,
- 'firstContentfulPaint', frame);
- if (firstContentfulPaintEvent === undefined)
- throw new Error(
- 'Failed to find firstContentfulPaintEvent for frame ' + frame);
+ ignoreRegions.push(warmCacheTimedEvent);
+ }
+ }, this);
- var grouping_keys = {};
+ return function isTelemetryInternalEvent(slice) {
+ for (var i = 0; i < ignoreRegions.length; ++ i) {
+ if (ignoreRegions[i].bounds(slice))
+ return true;
+ }
+ return false;
+ }
+ }
- var timeToFirstContentfulPaint =
- firstContentfulPaintEvent.start - navigationStartEvent.start;
+ var URL_BLACKLIST = ['about:blank'];
+ function shouldIgnoreURL(url) {
+ return URL_BLACKLIST.indexOf(url) >= 0;
+ }
+
+ function firstPaintMetric(values, model) {
+ var chromeHelper = model.getOrCreateHelper(
+ tr.model.helpers.ChromeModelHelper);
+ var rendererHelper = findTargetRendererHelper(chromeHelper);
+ var isTelemetryInternalEvent =
+ prepareTelemetryInternalEventPredicate(rendererHelper);
+ var findNavigationStartEventForFrameBeforeTimestamp =
+ navigationStartFinder(rendererHelper);
+
+ var numericBuilder =
+ new tr.v.NumericBuilder(timeDurationInMs_smallerIsBetter, 0)
+ .addLinearBins(1000, 20) // 50ms step to 1s
+ .addLinearBins(3000, 20) // 100ms step to 3s
+ .addExponentialBins(20000, 20);
+ var firstContentfulPaintHistogram = numericBuilder.build();
+ firstContentfulPaintHistogram.customizeSummaryOptions({
+ avg: true,
+ count: true,
+ max: true,
+ min: true,
+ std: true,
+ sum: false,
+ percentile: [0.90, 0.95, 0.99],
+ });
+
+ var firstPaintEvents = findFirstPaintEvents(rendererHelper,
+ 'firstContentfulPaint');
+ firstPaintEvents = firstPaintEvents.filter(
+ (ev) => !isTelemetryInternalEvent(ev));
+ firstPaintEvents.forEach(function(ev) {
+ var frameIdRef = ev.args['frame'];
+ var url = findUrlOfFrameAt(rendererHelper, frameIdRef, ev.start);
+ if (shouldIgnoreURL(url))
+ return;
+ var navigationStartEvent =
+ findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start);
+
+ var timeToFirstContentfulPaint = ev.start - navigationStartEvent.start;
+ firstContentfulPaintHistogram.add(timeToFirstContentfulPaint, {url: url});
+ }, this);
values.addValue(new tr.v.NumericValue(
- model.canonicalUrlThatCreatedThisTrace, 'firstContentfulPaint',
- new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter,
- timeToFirstContentfulPaint),
- { description: 'time to first contentful paint' },
- grouping_keys));
+ model.canonicalUrl, 'firstContentfulPaint',
+ firstContentfulPaintHistogram,
+ { description: 'time to first contentful paint' }));
}
firstPaintMetric.prototype = {
« no previous file with comments | « no previous file | tracing/tracing/metrics/system_health/first_paint_metric_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698