Chromium Code Reviews| 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 bbbcc22f14ecd72c49ebc7e8457a08a98cbea1af..a39b843abc46dc1d534e4e8c84b71e804cfb0646 100644 |
| --- a/tracing/tracing/metrics/system_health/first_paint_metric.html |
| +++ b/tracing/tracing/metrics/system_health/first_paint_metric.html |
| @@ -19,10 +19,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 +35,122 @@ 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 findUrlOfFrameAt(rendererHelper, frameIdRef, ts) { |
| + var url; |
| + |
| + var objects = rendererHelper.process.objects; |
| + var frameLoaderInstances = objects.instancesByTypeName_['FrameLoader']; |
| + frameLoaderInstances.forEach(function(instance) { |
| + var snapshot = instance.getSnapshotAt(ts); |
| + if (frameIdRef !== snapshot.args['frame']['id_ref']) |
| + return; |
| + |
| + url = snapshot.args['documentLoaderURL']; |
| + }, this); |
| + |
| + return url; |
| } |
| - function findFirstPaintEvent(rendererHelper, title, frame) { |
| - var firstPaintEvent = undefined; |
| + 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 prepareTelemetryInternalEventPredicate(rendererHelper) { |
| + var ignoreRegionSlices = []; |
| + rendererHelper.mainThread.asyncSliceGroup.iterateAllEventsInThisContainer( |
| + () => true, function(slice) { |
| + if (slice.title.match(/^telemetry\.internal/)) |
| + ignoreRegionSlices.push(slice); |
| + }, this); |
| + |
| + return function isTelemetryInternalEvent(slice) { |
| + for (var i = 0; i < ignoreRegionSlices.length; ++ i) { |
| + if (ignoreRegionSlices[i].bounds(slice)) |
| + return true; |
| + } |
| + return false; |
| + } |
| } |
| function firstPaintMetric(valueList, model) { |
| - var rendererHelper = findTargetRendererHelper(model); |
| - var navigationStartEvent = findNavigationStartEvent(rendererHelper); |
| - |
| - if (navigationStartEvent === undefined) |
| - throw new Error('Failed to find navigationStartEvent.'); |
| - |
| - var frame = navigationStartEvent.args['frame']; |
| - var firstContentfulPaintEvent = findFirstPaintEvent(rendererHelper, |
| - 'firstContentfulPaint', frame); |
| - if (firstContentfulPaintEvent === undefined) |
| - throw new Error( |
| - 'Failed to find firstContentfulPaintEvent for frame ' + frame); |
| - |
| - var grouping_keys = {}; |
| - |
| - var timeToFirstContentfulPaint = |
| - firstContentfulPaintEvent.start - navigationStartEvent.start; |
| - valueList.addValue(new tr.v.NumericValue( |
| - model.canonicalUrlThatCreatedThisTrace, 'firstContentfulPaint', |
| - new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter, |
| - timeToFirstContentfulPaint), |
| - { description: 'time to first contentful paint' }, |
| - grouping_keys)); |
| + var chromeHelper = model.getOrCreateHelper( |
| + tr.model.helpers.ChromeModelHelper); |
| + var rendererHelper = findTargetRendererHelper(chromeHelper); |
| + var isTelemetryInternalEvent = |
| + prepareTelemetryInternalEventPredicate(rendererHelper); |
| + var findNavigationStartEventForFrameBeforeTimestamp = |
| + navigationStartFinder(rendererHelper); |
| + |
| + 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); |
| + var navigationStartEvent = |
| + findNavigationStartEventForFrameBeforeTimestamp(frameIdRef, ev.start); |
| + |
| + var timeToFirstContentfulPaint = |
| + ev.start - navigationStartEvent.start; |
| + |
| + var grouping_keys = {url: url}; |
| + valueList.addValue(new tr.v.NumericValue( |
|
benjhayden
2016/05/10 19:54:46
Instead of several scalars, do you want to use a N
kouhei (in TOK)
2016/05/11 06:39:33
I think we want separate individual values, as his
nednguyen
2016/05/11 21:36:38
Why do you think the histogram doesn't make sense?
kouhei (in TOK)
2016/05/12 05:41:25
Added Numeric histogram, but not sure how we can u
nednguyen
2016/05/12 15:35:30
For future use cases of Pcv2, I can imagine we hav
|
| + model.canonicalUrlThatCreatedThisTrace, 'firstContentfulPaint', |
|
benjhayden
2016/05/10 20:25:43
This is spelled "model.canonicalUrl" now.
kouhei (in TOK)
2016/05/11 06:39:33
Done.
|
| + new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter, |
| + timeToFirstContentfulPaint), |
| + { description: 'time to first contentful paint' }, |
| + grouping_keys)); |
| + }, this); |
| } |
| firstPaintMetric.prototype = { |