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

Side by Side Diff: tracing/tracing/importer/find_input_expectations.html

Issue 2162963002: [polymer] Merge of master into polymer10-migration (Closed) Base URL: git@github.com:catapult-project/catapult.git@polymer10-migration
Patch Set: Merge polymer10-migration int polymer10-merge Created 4 years, 5 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 unified diff | Download patch
OLDNEW
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <!-- 2 <!--
3 Copyright (c) 2015 The Chromium Authors. All rights reserved. 3 Copyright (c) 2015 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be 4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file. 5 found in the LICENSE file.
6 --> 6 -->
7 7
8 <link rel="import" href="/tracing/base/range_utils.html"> 8 <link rel="import" href="/tracing/base/range_utils.html">
9 <link rel="import" href="/tracing/extras/chrome/cc/input_latency_async_slice.htm l"> 9 <link rel="import" href="/tracing/extras/chrome/cc/input_latency_async_slice.htm l">
10 <link rel="import" href="/tracing/importer/proto_expectation.html"> 10 <link rel="import" href="/tracing/importer/proto_expectation.html">
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 MOUSE_DRAG_TYPE_NAMES, 66 MOUSE_DRAG_TYPE_NAMES,
67 PINCH_TYPE_NAMES, 67 PINCH_TYPE_NAMES,
68 TAP_TYPE_NAMES, 68 TAP_TYPE_NAMES,
69 FLING_TYPE_NAMES, 69 FLING_TYPE_NAMES,
70 TOUCH_TYPE_NAMES, 70 TOUCH_TYPE_NAMES,
71 SCROLL_TYPE_NAMES 71 SCROLL_TYPE_NAMES
72 ); 72 );
73 73
74 var RENDERER_FLING_TITLE = 'InputHandlerProxy::HandleGestureFling::started'; 74 var RENDERER_FLING_TITLE = 'InputHandlerProxy::HandleGestureFling::started';
75 75
76 // TODO(benjhayden) share with rail_ir_finder
77 var CSS_ANIMATION_TITLE = 'Animation'; 76 var CSS_ANIMATION_TITLE = 'Animation';
78 77
79 // If there's less than this much time between the end of one event and the 78 // If there's less than this much time between the end of one event and the
80 // start of the next, then they might be merged. 79 // start of the next, then they might be merged.
81 // There was not enough thought given to this value, so if you have any slight 80 // There was not enough thought given to this value, so if you have any slight
82 // reason to change it, then please do so. It might also be good to split this 81 // reason to change it, then please do so. It might also be good to split this
83 // into multiple values. 82 // into multiple values.
84 var INPUT_MERGE_THRESHOLD_MS = 200; 83 var INPUT_MERGE_THRESHOLD_MS = 200;
85 var ANIMATION_MERGE_THRESHOLD_MS = 32; // 2x 60FPS frames 84 var ANIMATION_MERGE_THRESHOLD_MS = 32; // 2x 60FPS frames
86 85
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 cb.call(opt_this, event); 119 cb.call(opt_this, event);
121 } 120 }
122 }); 121 });
123 } 122 }
124 123
125 function causedFrame(event) { 124 function causedFrame(event) {
126 return event.associatedEvents.some( 125 return event.associatedEvents.some(
127 x => x.title === tr.model.helpers.IMPL_RENDERING_STATS); 126 x => x.title === tr.model.helpers.IMPL_RENDERING_STATS);
128 } 127 }
129 128
129 function getSortedFrameEventsByProcess(modelHelper) {
130 var frameEventsByPid = {};
131 tr.b.iterItems(modelHelper.rendererHelpers, function(pid, rendererHelper) {
132 frameEventsByPid[pid] = rendererHelper.getFrameEventsInRange(
133 tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds);
134 });
135 return frameEventsByPid;
136 }
137
130 function getSortedInputEvents(modelHelper) { 138 function getSortedInputEvents(modelHelper) {
131 var inputEvents = []; 139 var inputEvents = [];
132 140
133 var browserProcess = modelHelper.browserHelper.process; 141 var browserProcess = modelHelper.browserHelper.process;
134 var mainThread = browserProcess.findAtMostOneThreadNamed( 142 var mainThread = browserProcess.findAtMostOneThreadNamed(
135 'CrBrowserMain'); 143 'CrBrowserMain');
136 mainThread.asyncSliceGroup.iterateAllEvents(function(slice) { 144 for (var slice of mainThread.asyncSliceGroup.getDescendantEvents()) {
137 if (!slice.isTopLevel) 145 if (!slice.isTopLevel)
138 return; 146 continue;
139 147
140 if (!(slice instanceof tr.e.cc.InputLatencyAsyncSlice)) 148 if (!(slice instanceof tr.e.cc.InputLatencyAsyncSlice))
141 return; 149 continue;
142 150
143 // TODO(beaudoin): This should never happen but it does. Investigate 151 // TODO(beaudoin): This should never happen but it does. Investigate
144 // the trace linked at in #1567 and remove that when it's fixed. 152 // the trace linked at in #1567 and remove that when it's fixed.
145 if (isNaN(slice.start) || 153 if (isNaN(slice.start) ||
146 isNaN(slice.duration) || 154 isNaN(slice.duration) ||
147 isNaN(slice.end)) 155 isNaN(slice.end))
148 return; 156 continue;
149 157
150 inputEvents.push(slice); 158 inputEvents.push(slice);
151 }); 159 }
152 160
153 return inputEvents.sort(compareEvents); 161 return inputEvents.sort(compareEvents);
154 } 162 }
155 163
156 function findProtoExpectations(modelHelper, sortedInputEvents) { 164 function findProtoExpectations(modelHelper, sortedInputEvents) {
157 var protoExpectations = []; 165 var protoExpectations = [];
158 // This order is not important. Handlers are independent. 166 // This order is not important. Handlers are independent.
159 var handlers = [ 167 var handlers = [
160 handleKeyboardEvents, 168 handleKeyboardEvents,
161 handleMouseResponseEvents, 169 handleMouseResponseEvents,
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 // CSS Animations are merged into AnimationExpectations when they intersect. 725 // CSS Animations are merged into AnimationExpectations when they intersect.
718 function handleCSSAnimations(modelHelper, sortedInputEvents) { 726 function handleCSSAnimations(modelHelper, sortedInputEvents) {
719 // First find all the top-level CSS Animation async events. 727 // First find all the top-level CSS Animation async events.
720 var animationEvents = modelHelper.browserHelper. 728 var animationEvents = modelHelper.browserHelper.
721 getAllAsyncSlicesMatching(function(event) { 729 getAllAsyncSlicesMatching(function(event) {
722 return ((event.title === CSS_ANIMATION_TITLE) && 730 return ((event.title === CSS_ANIMATION_TITLE) &&
723 event.isTopLevel && 731 event.isTopLevel &&
724 (event.duration > 0)); 732 (event.duration > 0));
725 }); 733 });
726 734
727 // Memoize the frame events per process.
728 // There may be many Animation events for each process. We can save a
729 // significant amount of processing time by avoiding re-computing them for
730 // each animation.
731 var framesForProcess = {};
732
733 function getFramesForAnimationProcess(animation) {
734 var frames = framesForProcess[animation.parentContainer.parent.guid];
735 if (frames === undefined) {
736 var rendererHelper = new tr.model.helpers.ChromeRendererHelper(
737 modelHelper, animation.parentContainer.parent);
738 // Collect all the frame events in the same renderer process as the css
739 // animation, and memoize them.
740 frames = rendererHelper.getFrameEventsInRange(
741 tr.model.helpers.IMPL_FRAMETIME_TYPE, modelHelper.model.bounds);
742 framesForProcess[animation.parentContainer.parent.guid] = frames;
743 }
744 return frames;
745 }
746 735
747 // Time ranges where animations are actually running will be collected here. 736 // Time ranges where animations are actually running will be collected here.
748 // Each element will contain {min, max, animation, frames}. 737 // Each element will contain {min, max, animation}.
749 var animationRanges = []; 738 var animationRanges = [];
750 739
751 // This helper function will be called when a time range is found 740 // This helper function will be called when a time range is found
752 // during which the animation is actually running. 741 // during which the animation is actually running.
753 // This helper function collects the frames that happened during the time
754 // range, and pushes it all to |animationRanges|.
755 function pushAnimationRange(start, end, animation) { 742 function pushAnimationRange(start, end, animation) {
756 var range = tr.b.Range.fromExplicitRange(start, end); 743 var range = tr.b.Range.fromExplicitRange(start, end);
757 range.animation = animation; 744 range.animation = animation;
758
759 // Collect the frames that happened while the animation was running.
760 // A more general way to find these frames would be to collect all of
761 // the trace events caused by this animation, but that will require
762 // adding flow events to chrome:
763 // https://github.com/catapult-project/catapult/issues/1433
764 range.frames = range.filterArray(
765 getFramesForAnimationProcess(animation),
766 function(frameEvent) { return frameEvent.start; });
767
768 // If a tree falls in a forest...
769 // If there were not actually any frames while the animation was
770 // running, then it wasn't really an animation, now, was it?
771 // Philosophy aside, the system_health Animation metrics fail hard if
772 // there are no frames in an AnimationExpectation.
773 if (range.frames.length === 0)
774 return;
775
776 animationRanges.push(range); 745 animationRanges.push(range);
777 } 746 }
778 747
779 animationEvents.forEach(function(animation) { 748 animationEvents.forEach(function(animation) {
780 if (animation.subSlices.length === 0) { 749 if (animation.subSlices.length === 0) {
781 pushAnimationRange(animation.start, animation.end, animation); 750 pushAnimationRange(animation.start, animation.end, animation);
782 } else { 751 } else {
783 // Now run a state machine over the animation's subSlices, which 752 // Now run a state machine over the animation's subSlices, which
784 // indicate the animations running/paused/finished states, in order to 753 // indicate the animations running/paused/finished states, in order to
785 // find ranges where the animation was actually running. 754 // find ranges where the animation was actually running.
(...skipping 23 matching lines...) Expand all
809 } 778 }
810 }); 779 });
811 780
812 // An animation was still running when the trace ended. 781 // An animation was still running when the trace ended.
813 if (start !== undefined) 782 if (start !== undefined)
814 pushAnimationRange(start, modelHelper.model.bounds.max, animation); 783 pushAnimationRange(start, modelHelper.model.bounds.max, animation);
815 } 784 }
816 }); 785 });
817 786
818 // Now we have a set of time ranges when css animations were actually 787 // Now we have a set of time ranges when css animations were actually
819 // running, along with their frames. 788 // running.
820 // Now all that's left for this function is to merge over-lapping ranges 789 // Leave merging intersecting animations to mergeIntersectingAnimations(),
821 // into ProtoExpectations. 790 // after findFrameEventsForAnimations removes frame-less animations.
822 791
823 function merge(ranges) { 792 return animationRanges.map(function(range) {
824 var protoExpectation = new ProtoExpectation( 793 var protoExpectation = new ProtoExpectation(
825 ProtoExpectation.ANIMATION_TYPE, CSS_IR_NAME); 794 ProtoExpectation.ANIMATION_TYPE, CSS_IR_NAME);
826 ranges.forEach(function(range) { 795 protoExpectation.start = range.min;
827 protoExpectation.start = Math.min(protoExpectation.start, range.min); 796 protoExpectation.end = range.max;
828 protoExpectation.end = Math.max(protoExpectation.end, range.max); 797 protoExpectation.associatedEvents.push(range.animation);
829 protoExpectation.associatedEvents.push(range.animation);
830 protoExpectation.associatedEvents.addEventSet(range.frames);
831 });
832 return protoExpectation; 798 return protoExpectation;
833 } 799 });
834
835 return tr.b.mergeRanges(animationRanges,
836 ANIMATION_MERGE_THRESHOLD_MS,
837 merge);
838 } 800 }
839 801
840 function postProcessProtoExpectations(protoExpectations) { 802 function postProcessProtoExpectations(modelHelper, protoExpectations) {
841 // protoExpectations is input only. Returns a modified set of 803 // protoExpectations is input only. Returns a modified set of
842 // ProtoExpectations. The order is important. 804 // ProtoExpectations. The order is important.
805 protoExpectations = findFrameEventsForAnimations(
806 modelHelper, protoExpectations);
843 protoExpectations = mergeIntersectingResponses(protoExpectations); 807 protoExpectations = mergeIntersectingResponses(protoExpectations);
844 protoExpectations = mergeIntersectingAnimations(protoExpectations); 808 protoExpectations = mergeIntersectingAnimations(protoExpectations);
845 protoExpectations = fixResponseAnimationStarts(protoExpectations); 809 protoExpectations = fixResponseAnimationStarts(protoExpectations);
846 protoExpectations = fixTapResponseTouchAnimations(protoExpectations); 810 protoExpectations = fixTapResponseTouchAnimations(protoExpectations);
847 return protoExpectations; 811 return protoExpectations;
848 } 812 }
849 813
850 // TouchStarts happen at the same time as ScrollBegins. 814 // TouchStarts happen at the same time as ScrollBegins.
851 // It's easier to let multiple handlers create multiple overlapping 815 // It's easier to let multiple handlers create multiple overlapping
852 // Responses and then merge them, rather than make the handlers aware of the 816 // Responses and then merge them, rather than make the handlers aware of the
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 for (var i = 0; i < protoExpectations.length; ++i) { 886 for (var i = 0; i < protoExpectations.length; ++i) {
923 var otherPE = protoExpectations[i]; 887 var otherPE = protoExpectations[i];
924 888
925 if (otherPE.irType !== pe.irType) 889 if (otherPE.irType !== pe.irType)
926 continue; 890 continue;
927 891
928 // Don't merge CSS Animations with any other types. 892 // Don't merge CSS Animations with any other types.
929 if (isCSS != otherPE.containsSliceTitle(CSS_ANIMATION_TITLE)) 893 if (isCSS != otherPE.containsSliceTitle(CSS_ANIMATION_TITLE))
930 continue; 894 continue;
931 895
932 if (!otherPE.intersects(pe)) 896 if (isCSS) {
897 if (!pe.isNear(otherPE, ANIMATION_MERGE_THRESHOLD_MS))
898 continue;
899 } else if (!otherPE.intersects(pe)) {
933 continue; 900 continue;
901 }
934 902
935 // Don't merge Fling Animations with any other types. 903 // Don't merge Fling Animations with any other types.
936 if (isFling != otherPE.containsTypeNames([INPUT_TYPE.FLING_START])) 904 if (isFling != otherPE.containsTypeNames([INPUT_TYPE.FLING_START]))
937 continue; 905 continue;
938 906
939 pe.merge(otherPE); 907 pe.merge(otherPE);
940 protoExpectations.splice(i, 1); 908 protoExpectations.splice(i, 1);
941 // Don't skip the next otherPE! 909 // Don't skip the next otherPE!
942 --i; 910 --i;
943 } 911 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 992
1025 pe.merge(otherPE); 993 pe.merge(otherPE);
1026 protoExpectations.splice(i, 1); 994 protoExpectations.splice(i, 1);
1027 // Don't skip the next otherPE! 995 // Don't skip the next otherPE!
1028 --i; 996 --i;
1029 } 997 }
1030 } 998 }
1031 return newPEs; 999 return newPEs;
1032 } 1000 }
1033 1001
1002 function findFrameEventsForAnimations(modelHelper, protoExpectations) {
1003 var newPEs = [];
1004 var frameEventsByPid = getSortedFrameEventsByProcess(modelHelper);
1005
1006 for (var pe of protoExpectations) {
1007 if (pe.irType !== ProtoExpectation.ANIMATION_TYPE) {
1008 newPEs.push(pe);
1009 continue;
1010 }
1011
1012 var frameEvents = [];
1013 // TODO(benjhayden): Use frame blame contexts here.
1014 for (var pid of Object.keys(modelHelper.rendererHelpers)) {
1015 var range = tr.b.Range.fromExplicitRange(pe.start, pe.end);
1016 frameEvents.push.apply(frameEvents,
1017 range.filterArray(frameEventsByPid[pid], e => e.start));
1018 }
1019
1020 // If a tree falls in a forest...
1021 // If there were not actually any frames while the animation was
1022 // running, then it wasn't really an animation, now, was it?
1023 // Philosophy aside, the system_health Animation metrics fail hard if
1024 // there are no frames in an AnimationExpectation.
1025 if (frameEvents.length === 0) {
1026 pe.irType = ProtoExpectation.IGNORED_TYPE;
1027 newPEs.push(pe);
1028 continue;
1029 }
1030
1031 pe.associatedEvents.addEventSet(frameEvents);
1032 newPEs.push(pe);
1033 }
1034
1035 return newPEs;
1036 }
1037
1034 // Check that none of the handlers accidentally ignored an input event. 1038 // Check that none of the handlers accidentally ignored an input event.
1035 function checkAllInputEventsHandled(sortedInputEvents, protoExpectations) { 1039 function checkAllInputEventsHandled(sortedInputEvents, protoExpectations) {
1036 var handledEvents = []; 1040 var handledEvents = [];
1037 protoExpectations.forEach(function(protoExpectation) { 1041 protoExpectations.forEach(function(protoExpectation) {
1038 protoExpectation.associatedEvents.forEach(function(event) { 1042 protoExpectation.associatedEvents.forEach(function(event) {
1039 // Ignore CSS Animations that might have multiple active ranges. 1043 // Ignore CSS Animations that might have multiple active ranges.
1040 if ((event.title === CSS_ANIMATION_TITLE) && 1044 if ((event.title === CSS_ANIMATION_TITLE) &&
1041 (event.subSlices.length > 0)) 1045 (event.subSlices.length > 0))
1042 return; 1046 return;
1043 1047
(...skipping 12 matching lines...) Expand all
1056 event.typeName, parseInt(event.start), parseInt(event.end)); 1060 event.typeName, parseInt(event.start), parseInt(event.end));
1057 } 1061 }
1058 }); 1062 });
1059 } 1063 }
1060 1064
1061 // Find ProtoExpectations, post-process them, convert them to real IRs. 1065 // Find ProtoExpectations, post-process them, convert them to real IRs.
1062 function findInputExpectations(modelHelper) { 1066 function findInputExpectations(modelHelper) {
1063 var sortedInputEvents = getSortedInputEvents(modelHelper); 1067 var sortedInputEvents = getSortedInputEvents(modelHelper);
1064 var protoExpectations = findProtoExpectations( 1068 var protoExpectations = findProtoExpectations(
1065 modelHelper, sortedInputEvents); 1069 modelHelper, sortedInputEvents);
1066 protoExpectations = postProcessProtoExpectations(protoExpectations); 1070 protoExpectations = postProcessProtoExpectations(
1071 modelHelper, protoExpectations);
1067 checkAllInputEventsHandled(sortedInputEvents, protoExpectations); 1072 checkAllInputEventsHandled(sortedInputEvents, protoExpectations);
1068 1073
1069 var irs = []; 1074 var irs = [];
1070 protoExpectations.forEach(function(protoExpectation) { 1075 protoExpectations.forEach(function(protoExpectation) {
1071 var ir = protoExpectation.createInteractionRecord(modelHelper.model); 1076 var ir = protoExpectation.createInteractionRecord(modelHelper.model);
1072 if (ir) 1077 if (ir)
1073 irs.push(ir); 1078 irs.push(ir);
1074 }); 1079 });
1075 return irs; 1080 return irs;
1076 } 1081 }
1077 1082
1078 return { 1083 return {
1079 findInputExpectations: findInputExpectations, 1084 findInputExpectations: findInputExpectations,
1080 compareEvents: compareEvents, 1085 compareEvents: compareEvents,
1081 CSS_ANIMATION_TITLE: CSS_ANIMATION_TITLE 1086 CSS_ANIMATION_TITLE: CSS_ANIMATION_TITLE
1082 }; 1087 };
1083 }); 1088 });
1084 </script> 1089 </script>
OLDNEW
« no previous file with comments | « tracing/tracing/extras/vsync/vsync_auditor_test.html ('k') | tracing/tracing/importer/find_load_expectations.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698