Chromium Code Reviews| 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 |