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 |