Index: tracing/tracing/importer/find_input_expectations.html |
diff --git a/tracing/tracing/importer/find_input_expectations.html b/tracing/tracing/importer/find_input_expectations.html |
index c59cc6e2f369b07eb38f32be4ccf036f0807574d..2e5092cb7ff42087dea718e71f190c1469c8a726 100644 |
--- a/tracing/tracing/importer/find_input_expectations.html |
+++ b/tracing/tracing/importer/find_input_expectations.html |
@@ -73,7 +73,6 @@ tr.exportTo('tr.importer', function() { |
var RENDERER_FLING_TITLE = 'InputHandlerProxy::HandleGestureFling::started'; |
- // TODO(benjhayden) share with rail_ir_finder |
var CSS_ANIMATION_TITLE = 'Animation'; |
// If there's less than this much time between the end of one event and the |
@@ -127,28 +126,37 @@ tr.exportTo('tr.importer', function() { |
x => x.title === tr.model.helpers.IMPL_RENDERING_STATS); |
} |
+ function getSortedFrameEventsByProcess(modelHelper) { |
+ var frameEventsByPid = {}; |
+ tr.b.iterItems(modelHelper.rendererHelpers, function(pid, rendererHelper) { |
+ frameEventsByPid[pid] = rendererHelper.getFrameEventsInRange( |
+ tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds); |
+ }); |
+ return frameEventsByPid; |
+ } |
+ |
function getSortedInputEvents(modelHelper) { |
var inputEvents = []; |
var browserProcess = modelHelper.browserHelper.process; |
var mainThread = browserProcess.findAtMostOneThreadNamed( |
'CrBrowserMain'); |
- mainThread.asyncSliceGroup.iterateAllEvents(function(slice) { |
+ for (var slice of mainThread.asyncSliceGroup.getDescendantEvents()) { |
if (!slice.isTopLevel) |
- return; |
+ continue; |
if (!(slice instanceof tr.e.cc.InputLatencyAsyncSlice)) |
- return; |
+ continue; |
// TODO(beaudoin): This should never happen but it does. Investigate |
// the trace linked at in #1567 and remove that when it's fixed. |
if (isNaN(slice.start) || |
isNaN(slice.duration) || |
isNaN(slice.end)) |
- return; |
+ continue; |
inputEvents.push(slice); |
- }); |
+ } |
return inputEvents.sort(compareEvents); |
} |
@@ -724,55 +732,16 @@ tr.exportTo('tr.importer', function() { |
(event.duration > 0)); |
}); |
- // Memoize the frame events per process. |
- // There may be many Animation events for each process. We can save a |
- // significant amount of processing time by avoiding re-computing them for |
- // each animation. |
- var framesForProcess = {}; |
- |
- function getFramesForAnimationProcess(animation) { |
- var frames = framesForProcess[animation.parentContainer.parent.guid]; |
- if (frames === undefined) { |
- var rendererHelper = new tr.model.helpers.ChromeRendererHelper( |
- modelHelper, animation.parentContainer.parent); |
- // Collect all the frame events in the same renderer process as the css |
- // animation, and memoize them. |
- frames = rendererHelper.getFrameEventsInRange( |
- tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds); |
- framesForProcess[animation.parentContainer.parent.guid] = frames; |
- } |
- return frames; |
- } |
// Time ranges where animations are actually running will be collected here. |
- // Each element will contain {min, max, animation, frames}. |
+ // Each element will contain {min, max, animation}. |
var animationRanges = []; |
// This helper function will be called when a time range is found |
// during which the animation is actually running. |
- // This helper function collects the frames that happened during the time |
- // range, and pushes it all to |animationRanges|. |
function pushAnimationRange(start, end, animation) { |
var range = tr.b.Range.fromExplicitRange(start, end); |
range.animation = animation; |
- |
- // Collect the frames that happened while the animation was running. |
- // A more general way to find these frames would be to collect all of |
- // the trace events caused by this animation, but that will require |
- // adding flow events to chrome: |
- // https://github.com/catapult-project/catapult/issues/1433 |
- range.frames = range.filterArray( |
- getFramesForAnimationProcess(animation), |
- function(frameEvent) { return frameEvent.start; }); |
- |
- // If a tree falls in a forest... |
- // If there were not actually any frames while the animation was |
- // running, then it wasn't really an animation, now, was it? |
- // Philosophy aside, the system_health Animation metrics fail hard if |
- // there are no frames in an AnimationExpectation. |
- if (range.frames.length === 0) |
- return; |
- |
animationRanges.push(range); |
} |
@@ -816,30 +785,25 @@ tr.exportTo('tr.importer', function() { |
}); |
// Now we have a set of time ranges when css animations were actually |
- // running, along with their frames. |
- // Now all that's left for this function is to merge over-lapping ranges |
- // into ProtoExpectations. |
+ // running. |
+ // Leave merging intersecting animations to mergeIntersectingAnimations(), |
+ // after findFrameEventsForAnimations removes frame-less animations. |
- function merge(ranges) { |
+ return animationRanges.map(function(range) { |
var protoExpectation = new ProtoExpectation( |
ProtoExpectation.ANIMATION_TYPE, CSS_IR_NAME); |
- ranges.forEach(function(range) { |
- protoExpectation.start = Math.min(protoExpectation.start, range.min); |
- protoExpectation.end = Math.max(protoExpectation.end, range.max); |
- protoExpectation.associatedEvents.push(range.animation); |
- protoExpectation.associatedEvents.addEventSet(range.frames); |
- }); |
+ protoExpectation.start = range.min; |
+ protoExpectation.end = range.max; |
+ protoExpectation.associatedEvents.push(range.animation); |
return protoExpectation; |
- } |
- |
- return tr.b.mergeRanges(animationRanges, |
- ANIMATION_MERGE_THRESHOLD_MS, |
- merge); |
+ }); |
} |
- function postProcessProtoExpectations(protoExpectations) { |
+ function postProcessProtoExpectations(modelHelper, protoExpectations) { |
// protoExpectations is input only. Returns a modified set of |
// ProtoExpectations. The order is important. |
+ protoExpectations = findFrameEventsForAnimations( |
+ modelHelper, protoExpectations); |
protoExpectations = mergeIntersectingResponses(protoExpectations); |
protoExpectations = mergeIntersectingAnimations(protoExpectations); |
protoExpectations = fixResponseAnimationStarts(protoExpectations); |
@@ -929,8 +893,12 @@ tr.exportTo('tr.importer', function() { |
if (isCSS != otherPE.containsSliceTitle(CSS_ANIMATION_TITLE)) |
continue; |
- if (!otherPE.intersects(pe)) |
+ if (isCSS) { |
+ if (!pe.isNear(otherPE, ANIMATION_MERGE_THRESHOLD_MS)) |
+ continue; |
+ } else if (!otherPE.intersects(pe)) { |
continue; |
+ } |
// Don't merge Fling Animations with any other types. |
if (isFling != otherPE.containsTypeNames([INPUT_TYPE.FLING_START])) |
@@ -1031,6 +999,42 @@ tr.exportTo('tr.importer', function() { |
return newPEs; |
} |
+ function findFrameEventsForAnimations(modelHelper, protoExpectations) { |
+ var newPEs = []; |
+ var frameEventsByPid = getSortedFrameEventsByProcess(modelHelper); |
+ |
+ for (var pe of protoExpectations) { |
+ if (pe.irType !== ProtoExpectation.ANIMATION_TYPE) { |
+ newPEs.push(pe); |
+ continue; |
+ } |
+ |
+ var frameEvents = []; |
+ // TODO(benjhayden): Use frame blame contexts here. |
+ for (var pid of Object.keys(modelHelper.rendererHelpers)) { |
+ var range = tr.b.Range.fromExplicitRange(pe.start, pe.end); |
+ frameEvents.push.apply(frameEvents, |
+ range.filterArray(frameEventsByPid[pid], e => e.start)); |
+ } |
+ |
+ // If a tree falls in a forest... |
+ // If there were not actually any frames while the animation was |
+ // running, then it wasn't really an animation, now, was it? |
+ // Philosophy aside, the system_health Animation metrics fail hard if |
+ // there are no frames in an AnimationExpectation. |
+ if (frameEvents.length === 0) { |
+ pe.irType = ProtoExpectation.IGNORED_TYPE; |
+ newPEs.push(pe); |
+ continue; |
+ } |
+ |
+ pe.associatedEvents.addEventSet(frameEvents); |
+ newPEs.push(pe); |
+ } |
+ |
+ return newPEs; |
+ } |
+ |
// Check that none of the handlers accidentally ignored an input event. |
function checkAllInputEventsHandled(sortedInputEvents, protoExpectations) { |
var handledEvents = []; |
@@ -1063,7 +1067,8 @@ tr.exportTo('tr.importer', function() { |
var sortedInputEvents = getSortedInputEvents(modelHelper); |
var protoExpectations = findProtoExpectations( |
modelHelper, sortedInputEvents); |
- protoExpectations = postProcessProtoExpectations(protoExpectations); |
+ protoExpectations = postProcessProtoExpectations( |
+ modelHelper, protoExpectations); |
checkAllInputEventsHandled(sortedInputEvents, protoExpectations); |
var irs = []; |