| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 import Queue | 5 import Queue |
| 6 import datetime | 6 import datetime |
| 7 import logging | 7 import logging |
| 8 import re | 8 import re |
| 9 import threading | 9 import threading |
| 10 | 10 |
| 11 from pylib import perf_tests_helper | 11 from pylib import perf_tests_helper |
| 12 | 12 |
| 13 | 13 |
| 14 # Log marker containing SurfaceTexture timestamps. | 14 # Log marker containing SurfaceTexture timestamps. |
| 15 _SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps' | 15 _SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps' |
| 16 _SURFACE_TEXTURE_TIMESTAMP_RE = '\d+' | 16 _SURFACE_TEXTURE_TIMESTAMP_RE = '\d+' |
| 17 | 17 |
| 18 | 18 |
| 19 class SurfaceStatsCollector(object): | 19 class SurfaceStatsCollector(object): |
| 20 """Collects surface stats for a window from the output of SurfaceFlinger. | 20 """Collects surface stats for a SurfaceView from the output of SurfaceFlinger. |
| 21 | 21 |
| 22 Args: | 22 Args: |
| 23 adb: the adb coonection to use. | 23 adb: the adb connection to use. |
| 24 window_package: Package name of the window. | |
| 25 window_activity: Activity name of the window. | |
| 26 """ | 24 """ |
| 27 def __init__(self, adb, window_package, window_activity, trace_tag): | 25 def __init__(self, adb, trace_tag): |
| 28 self._adb = adb | 26 self._adb = adb |
| 29 self._window_package = window_package | |
| 30 self._window_activity = window_activity | |
| 31 self._trace_tag = trace_tag | 27 self._trace_tag = trace_tag |
| 32 self._collector_thread = None | 28 self._collector_thread = None |
| 33 self._use_legacy_method = False | 29 self._use_legacy_method = False |
| 34 self._surface_before = None | 30 self._surface_before = None |
| 35 self._get_data_event = None | 31 self._get_data_event = None |
| 36 self._data_queue = None | 32 self._data_queue = None |
| 37 self._stop_event = None | 33 self._stop_event = None |
| 38 | 34 |
| 39 def __enter__(self): | 35 def __enter__(self): |
| 40 assert not self._collector_thread | 36 assert not self._collector_thread |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 def _ClearSurfaceFlingerLatencyData(self): | 140 def _ClearSurfaceFlingerLatencyData(self): |
| 145 """Clears the SurfaceFlinger latency data. | 141 """Clears the SurfaceFlinger latency data. |
| 146 | 142 |
| 147 Returns: | 143 Returns: |
| 148 True if SurfaceFlinger latency is supported by the device, otherwise | 144 True if SurfaceFlinger latency is supported by the device, otherwise |
| 149 False. | 145 False. |
| 150 """ | 146 """ |
| 151 # The command returns nothing if it is supported, otherwise returns many | 147 # The command returns nothing if it is supported, otherwise returns many |
| 152 # lines of result just like 'dumpsys SurfaceFlinger'. | 148 # lines of result just like 'dumpsys SurfaceFlinger'. |
| 153 results = self._adb.RunShellCommand( | 149 results = self._adb.RunShellCommand( |
| 154 'dumpsys SurfaceFlinger --latency-clear %s/%s' % | 150 'dumpsys SurfaceFlinger --latency-clear SurfaceView') |
| 155 (self._window_package, self._window_activity)) | |
| 156 return not len(results) | 151 return not len(results) |
| 157 | 152 |
| 158 def _GetSurfaceFlingerLatencyData(self, previous_timestamp, latencies): | 153 def _GetSurfaceFlingerLatencyData(self, previous_timestamp, latencies): |
| 159 """Returns collected SurfaceFlinger latency data. | 154 """Returns collected SurfaceFlinger latency data. |
| 160 | 155 |
| 161 Args: | 156 Args: |
| 162 previous_timestamp: The timestamp returned from the previous call or 0. | 157 previous_timestamp: The timestamp returned from the previous call or 0. |
| 163 Only data after this timestamp will be returned. | 158 Only data after this timestamp will be returned. |
| 164 latencies: A list to receive latency data. The latencies are integers | 159 latencies: A list to receive latency data. The latencies are integers |
| 165 each of which is the number of refresh periods of each frame. | 160 each of which is the number of refresh periods of each frame. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 189 # | 184 # |
| 190 # The difference between the 1st and 3rd timestamp is the frame-latency. | 185 # The difference between the 1st and 3rd timestamp is the frame-latency. |
| 191 # An interesting data is when the frame latency crosses a refresh period | 186 # An interesting data is when the frame latency crosses a refresh period |
| 192 # boundary, this can be calculated this way: | 187 # boundary, this can be calculated this way: |
| 193 # | 188 # |
| 194 # ceil((C - A) / refresh-period) | 189 # ceil((C - A) / refresh-period) |
| 195 # | 190 # |
| 196 # (each time the number above changes, we have a "jank"). | 191 # (each time the number above changes, we have a "jank"). |
| 197 # If this happens a lot during an animation, the animation appears | 192 # If this happens a lot during an animation, the animation appears |
| 198 # janky, even if it runs at 60 fps in average. | 193 # janky, even if it runs at 60 fps in average. |
| 194 # |
| 195 # We use the special "SurfaceView" window name because the statistics for |
| 196 # the activity's main window are not updated when the main web content is |
| 197 # composited into a SurfaceView. |
| 199 results = self._adb.RunShellCommand( | 198 results = self._adb.RunShellCommand( |
| 200 'dumpsys SurfaceFlinger --latency %s/%s' % | 199 'dumpsys SurfaceFlinger --latency SurfaceView', log_result=True) |
| 201 (self._window_package, self._window_activity), log_result=True) | |
| 202 if not len(results): | 200 if not len(results): |
| 203 return (None, None) | 201 return (None, None) |
| 204 | 202 |
| 205 refresh_period = int(results[0]) | 203 refresh_period = int(results[0]) |
| 206 last_timestamp = previous_timestamp | 204 last_timestamp = previous_timestamp |
| 207 first_timestamp = 0 | 205 first_timestamp = 0 |
| 208 for line in results[1:]: | 206 for line in results[1:]: |
| 209 fields = line.split() | 207 fields = line.split() |
| 210 if len(fields) == 3: | 208 if len(fields) == 3: |
| 211 timestamp = long(fields[0]) | 209 timestamp = long(fields[0]) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 236 try: | 234 try: |
| 237 cur_surface = int(match.group(1), 16) | 235 cur_surface = int(match.group(1), 16) |
| 238 except Exception: | 236 except Exception: |
| 239 logging.error('Failed to parse current surface from ' + match.group(1)) | 237 logging.error('Failed to parse current surface from ' + match.group(1)) |
| 240 else: | 238 else: |
| 241 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) | 239 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) |
| 242 return { | 240 return { |
| 243 'page_flip_count': cur_surface, | 241 'page_flip_count': cur_surface, |
| 244 'timestamp': datetime.datetime.now(), | 242 'timestamp': datetime.datetime.now(), |
| 245 } | 243 } |
| OLD | NEW |