OLD | NEW |
---|---|
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Identifies key events related to user satisfaction. | 5 """Identifies key events related to user satisfaction. |
6 | 6 |
7 Several lenses are defined, for example FirstTextPaintLens and | 7 Several lenses are defined, for example FirstTextPaintLens and |
8 FirstSignificantPaintLens. | 8 FirstSignificantPaintLens. |
9 """ | 9 """ |
10 import logging | 10 import logging |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
84 return [rq for rq in request_track.GetEvents() | 84 return [rq for rq in request_track.GetEvents() |
85 if rq.end_msec <= time_ms] | 85 if rq.end_msec <= time_ms] |
86 | 86 |
87 | 87 |
88 class _FirstEventLens(_UserSatisfiedLens): | 88 class _FirstEventLens(_UserSatisfiedLens): |
89 """Helper abstract subclass that defines users first event manipulations.""" | 89 """Helper abstract subclass that defines users first event manipulations.""" |
90 # pylint can't handle abstract subclasses. | 90 # pylint can't handle abstract subclasses. |
91 # pylint: disable=abstract-method | 91 # pylint: disable=abstract-method |
92 | 92 |
93 @classmethod | 93 @classmethod |
94 def _CheckCategory(cls, tracing_track, category): | |
95 assert category in tracing_track.Categories(), ( | |
96 'The "%s" category must be enabled.' % category) | |
97 | |
98 @classmethod | |
94 def _ExtractFirstTiming(cls, times): | 99 def _ExtractFirstTiming(cls, times): |
95 if not times: | 100 if not times: |
96 return float('inf') | 101 return float('inf') |
97 if len(times) != 1: | 102 if len(times) != 1: |
98 # TODO(mattcary): in some cases a trace has two first paint events. Why? | 103 # TODO(mattcary): in some cases a trace has two first paint events. Why? |
99 logging.error('%d %s with spread of %s', len(times), | 104 logging.error('%d %s with spread of %s', len(times), |
100 str(cls), max(times) - min(times)) | 105 str(cls), max(times) - min(times)) |
101 return float(min(times)) | 106 return float(min(times)) |
102 | 107 |
103 | 108 |
104 class FirstTextPaintLens(_FirstEventLens): | 109 class FirstTextPaintLens(_FirstEventLens): |
105 """Define satisfaction by the first text paint. | 110 """Define satisfaction by the first text paint. |
106 | 111 |
107 This event is taken directly from a trace. | 112 This event is taken directly from a trace. |
108 """ | 113 """ |
114 _EVENT_CATEGORY = 'blink.user_timing' | |
109 def _CalculateTimes(self, tracing_track): | 115 def _CalculateTimes(self, tracing_track): |
116 self._CheckCategory(tracing_track, self._EVENT_CATEGORY) | |
110 first_paints = [e.start_msec for e in tracing_track.GetEvents() | 117 first_paints = [e.start_msec for e in tracing_track.GetEvents() |
111 if e.Matches('blink.user_timing', 'firstPaint')] | 118 if e.Matches(self._EVENT_CATEGORY, 'firstPaint')] |
112 self._satisfied_msec = self._event_msec = \ | 119 self._satisfied_msec = self._event_msec = \ |
113 self._ExtractFirstTiming(first_paints) | 120 self._ExtractFirstTiming(first_paints) |
114 | 121 |
115 | 122 |
116 class FirstContentfulPaintLens(_FirstEventLens): | 123 class FirstContentfulPaintLens(_FirstEventLens): |
117 """Define satisfaction by the first contentful paint. | 124 """Define satisfaction by the first contentful paint. |
118 | 125 |
119 This event is taken directly from a trace. Internally to chrome it's computed | 126 This event is taken directly from a trace. Internally to chrome it's computed |
120 by filtering out things like background paint from firstPaint. | 127 by filtering out things like background paint from firstPaint. |
121 """ | 128 """ |
129 _EVENT_CATEGORY = 'blink.user_timing' | |
122 def _CalculateTimes(self, tracing_track): | 130 def _CalculateTimes(self, tracing_track): |
131 self._CheckCategory(tracing_track, self._EVENT_CATEGORY) | |
123 first_paints = [e.start_msec for e in tracing_track.GetEvents() | 132 first_paints = [e.start_msec for e in tracing_track.GetEvents() |
124 if e.Matches('blink.user_timing', 'firstContentfulPaint')] | 133 if e.Matches(self._EVENT_CATEGORY, 'firstContentfulPaint')] |
125 self._satisfied_msec = self._event_msec = \ | 134 self._satisfied_msec = self._event_msec = \ |
126 self._ExtractFirstTiming(first_paints) | 135 self._ExtractFirstTiming(first_paints) |
127 | 136 |
128 | 137 |
129 class FirstSignificantPaintLens(_FirstEventLens): | 138 class FirstSignificantPaintLens(_FirstEventLens): |
130 """Define satisfaction by the first paint after a big layout change. | 139 """Define satisfaction by the first paint after a big layout change. |
131 | 140 |
132 Our satisfaction time is that of the layout change, as all resources must have | 141 Our satisfaction time is that of the layout change, as all resources must have |
133 been loaded to compute the layout. Our event time is that of the next paint as | 142 been loaded to compute the layout. Our event time is that of the next paint as |
134 that is the observable event. | 143 that is the observable event. |
135 """ | 144 """ |
136 FIRST_LAYOUT_COUNTER = 'LayoutObjectsThatHadNeverHadLayout' | 145 FIRST_LAYOUT_COUNTER = 'LayoutObjectsThatHadNeverHadLayout' |
mattcary
2016/04/27 08:00:04
While you're in here add an underscore to FIRST_LA
| |
137 | 146 _EVENT_CATEGORY = 'disabled-by-default-blink.debug.layout' |
138 def _CalculateTimes(self, tracing_track): | 147 def _CalculateTimes(self, tracing_track): |
148 self._CheckCategory(tracing_track, self._EVENT_CATEGORY) | |
139 sync_paint_times = [] | 149 sync_paint_times = [] |
140 layouts = [] # (layout item count, msec). | 150 layouts = [] # (layout item count, msec). |
141 for e in tracing_track.GetEvents(): | 151 for e in tracing_track.GetEvents(): |
142 # TODO(mattcary): is this the right paint event? Check if synchronized | 152 # TODO(mattcary): is this the right paint event? Check if synchronized |
143 # paints appear at the same time as the first*Paint events, above. | 153 # paints appear at the same time as the first*Paint events, above. |
144 if e.Matches('blink', 'FrameView::SynchronizedPaint'): | 154 if e.Matches('blink', 'FrameView::SynchronizedPaint'): |
145 sync_paint_times.append(e.start_msec) | 155 sync_paint_times.append(e.start_msec) |
146 if ('counters' in e.args and | 156 if ('counters' in e.args and |
147 self.FIRST_LAYOUT_COUNTER in e.args['counters']): | 157 self.FIRST_LAYOUT_COUNTER in e.args['counters']): |
148 layouts.append((e.args['counters'][self.FIRST_LAYOUT_COUNTER], | 158 layouts.append((e.args['counters'][self.FIRST_LAYOUT_COUNTER], |
149 e.start_msec)) | 159 e.start_msec)) |
150 assert layouts, ('No layout events, was the disabled-by-default-blink' | 160 assert layouts, 'No layout events' |
151 '.debug.layout category enabled?') | |
152 layouts.sort(key=operator.itemgetter(0), reverse=True) | 161 layouts.sort(key=operator.itemgetter(0), reverse=True) |
153 self._satisfied_msec = layouts[0][1] | 162 self._satisfied_msec = layouts[0][1] |
154 self._event_msec = self._ExtractFirstTiming([ | 163 self._event_msec = self._ExtractFirstTiming([ |
155 min(t for t in sync_paint_times if t > self._satisfied_msec)]) | 164 min(t for t in sync_paint_times if t > self._satisfied_msec)]) |
OLD | NEW |