| 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 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 | 89 |
| 90 print 'SurfaceMonitorTime: %fsecs' % seconds | 90 print 'SurfaceMonitorTime: %fsecs' % seconds |
| 91 perf_tests_helper.PrintPerfResult( | 91 perf_tests_helper.PrintPerfResult( |
| 92 'avg_surface_fps', 'avg_surface_fps' + self._trace_tag, | 92 'avg_surface_fps', 'avg_surface_fps' + self._trace_tag, |
| 93 [int(round(frame_count / seconds))], 'fps') | 93 [int(round(frame_count / seconds))], 'fps') |
| 94 | 94 |
| 95 def _CollectorThread(self): | 95 def _CollectorThread(self): |
| 96 last_timestamp = 0 | 96 last_timestamp = 0 |
| 97 first_timestamp = 0 | 97 first_timestamp = 0 |
| 98 latencies = [] | 98 latencies = [] |
| 99 retries = 0 |
| 100 has_collected_data = False |
| 99 | 101 |
| 100 while not self._stop_event.is_set(): | 102 while not self._stop_event.is_set(): |
| 101 self._get_data_event.wait(1) | 103 self._get_data_event.wait(1) |
| 102 try: | 104 try: |
| 103 (t, last_timestamp) = self._GetSurfaceFlingerLatencyData(last_timestamp, | 105 (t, last_timestamp) = self._GetSurfaceFlingerLatencyData(last_timestamp, |
| 104 latencies) | 106 latencies) |
| 107 if (t, last_timestamp) == (None, None): |
| 108 retries += 1 |
| 109 if retries < 3: |
| 110 continue |
| 111 if has_collected_data: |
| 112 # Some data has already been collected, but either the app |
| 113 # was closed or there's no new data. Signal the main thread and |
| 114 # wait. |
| 115 self._data_queue.put((None, None)) |
| 116 self._stop_event.wait() |
| 117 break |
| 118 raise Exception('Unable to get surface flinger latency data') |
| 119 |
| 120 has_collected_data = True |
| 121 |
| 105 if not first_timestamp: | 122 if not first_timestamp: |
| 106 first_timestamp = t | 123 first_timestamp = t |
| 107 | 124 |
| 108 if self._get_data_event.is_set(): | 125 if self._get_data_event.is_set(): |
| 109 self._get_data_event.clear() | 126 self._get_data_event.clear() |
| 110 self._data_queue.put(((last_timestamp - first_timestamp) / 1e9, | 127 self._data_queue.put(((last_timestamp - first_timestamp) / 1e9, |
| 111 latencies)) | 128 latencies)) |
| 112 latencies = [] | 129 latencies = [] |
| 113 first_timestamp = 0 | 130 first_timestamp = 0 |
| 114 except Exception as e: | 131 except Exception as e: |
| (...skipping 29 matching lines...) Expand all Loading... |
| 144 Args: | 161 Args: |
| 145 previous_timestamp: The timestamp returned from the previous call or 0. | 162 previous_timestamp: The timestamp returned from the previous call or 0. |
| 146 Only data after this timestamp will be returned. | 163 Only data after this timestamp will be returned. |
| 147 latencies: A list to receive latency data. The latencies are integers | 164 latencies: A list to receive latency data. The latencies are integers |
| 148 each of which is the number of refresh periods of each frame. | 165 each of which is the number of refresh periods of each frame. |
| 149 | 166 |
| 150 Returns: | 167 Returns: |
| 151 A tuple containing: | 168 A tuple containing: |
| 152 - The timestamp of the beginning of the first frame (ns), | 169 - The timestamp of the beginning of the first frame (ns), |
| 153 - The timestamp of the end of the last frame (ns). | 170 - The timestamp of the end of the last frame (ns). |
| 154 | 171 The tuple may be (None, None) if there was no data collected (for example, |
| 155 Raises: | 172 if the app was closed before the collector thread has finished). |
| 156 Exception if failed to run the SurfaceFlinger command or SurfaceFlinger | |
| 157 returned invalid result. | |
| 158 """ | 173 """ |
| 159 # adb shell dumpsys SurfaceFlinger --latency <window name> | 174 # adb shell dumpsys SurfaceFlinger --latency <window name> |
| 160 # prints some information about the last 128 frames displayed in | 175 # prints some information about the last 128 frames displayed in |
| 161 # that window. | 176 # that window. |
| 162 # The data returned looks like this: | 177 # The data returned looks like this: |
| 163 # 16954612 | 178 # 16954612 |
| 164 # 7657467895508 7657482691352 7657493499756 | 179 # 7657467895508 7657482691352 7657493499756 |
| 165 # 7657484466553 7657499645964 7657511077881 | 180 # 7657484466553 7657499645964 7657511077881 |
| 166 # 7657500793457 7657516600576 7657527404785 | 181 # 7657500793457 7657516600576 7657527404785 |
| 167 # (...) | 182 # (...) |
| 168 # | 183 # |
| 169 # The first line is the refresh period (here 16.95 ms), it is followed | 184 # The first line is the refresh period (here 16.95 ms), it is followed |
| 170 # by 128 lines w/ 3 timestamps in nanosecond each: | 185 # by 128 lines w/ 3 timestamps in nanosecond each: |
| 171 # A) when the app started to draw | 186 # A) when the app started to draw |
| 172 # B) the vsync immediately preceding SF submitting the frame to the h/w | 187 # B) the vsync immediately preceding SF submitting the frame to the h/w |
| 173 # C) timestamp immediately after SF submitted that frame to the h/w | 188 # C) timestamp immediately after SF submitted that frame to the h/w |
| 174 # | 189 # |
| 175 # The difference between the 1st and 3rd timestamp is the frame-latency. | 190 # The difference between the 1st and 3rd timestamp is the frame-latency. |
| 176 # An interesting data is when the frame latency crosses a refresh period | 191 # An interesting data is when the frame latency crosses a refresh period |
| 177 # boundary, this can be calculated this way: | 192 # boundary, this can be calculated this way: |
| 178 # | 193 # |
| 179 # ceil((C - A) / refresh-period) | 194 # ceil((C - A) / refresh-period) |
| 180 # | 195 # |
| 181 # (each time the number above changes, we have a "jank"). | 196 # (each time the number above changes, we have a "jank"). |
| 182 # If this happens a lot during an animation, the animation appears | 197 # If this happens a lot during an animation, the animation appears |
| 183 # janky, even if it runs at 60 fps in average. | 198 # janky, even if it runs at 60 fps in average. |
| 184 results = self._adb.RunShellCommand( | 199 results = self._adb.RunShellCommand( |
| 185 'dumpsys SurfaceFlinger --latency %s/%s' % | 200 'dumpsys SurfaceFlinger --latency %s/%s' % |
| 186 (self._window_package, self._window_activity), log_result=True) | 201 (self._window_package, self._window_activity), log_result=True) |
| 187 assert len(results) | 202 if not len(results): |
| 203 return (None, None) |
| 188 | 204 |
| 189 refresh_period = int(results[0]) | 205 refresh_period = int(results[0]) |
| 190 last_timestamp = previous_timestamp | 206 last_timestamp = previous_timestamp |
| 191 first_timestamp = 0 | 207 first_timestamp = 0 |
| 192 for line in results[1:]: | 208 for line in results[1:]: |
| 193 fields = line.split() | 209 fields = line.split() |
| 194 if len(fields) == 3: | 210 if len(fields) == 3: |
| 195 timestamp = long(fields[0]) | 211 timestamp = long(fields[0]) |
| 196 last_timestamp = long(fields[2]) | 212 last_timestamp = long(fields[2]) |
| 197 if (timestamp > previous_timestamp): | 213 if (timestamp > previous_timestamp): |
| (...skipping 22 matching lines...) Expand all Loading... |
| 220 try: | 236 try: |
| 221 cur_surface = int(match.group(1), 16) | 237 cur_surface = int(match.group(1), 16) |
| 222 except Exception: | 238 except Exception: |
| 223 logging.error('Failed to parse current surface from ' + match.group(1)) | 239 logging.error('Failed to parse current surface from ' + match.group(1)) |
| 224 else: | 240 else: |
| 225 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) | 241 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) |
| 226 return { | 242 return { |
| 227 'page_flip_count': cur_surface, | 243 'page_flip_count': cur_surface, |
| 228 'timestamp': datetime.datetime.now(), | 244 'timestamp': datetime.datetime.now(), |
| 229 } | 245 } |
| OLD | NEW |