OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 | 11 |
12 # Log marker containing SurfaceTexture timestamps. | 12 # Log marker containing SurfaceTexture timestamps. |
13 _SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps' | 13 _SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps' |
14 _SURFACE_TEXTURE_TIMESTAMP_RE = '\d+' | 14 _SURFACE_TEXTURE_TIMESTAMP_RE = '\d+' |
15 | 15 |
| 16 _MIN_NORMALIZED_FRAME_LENGTH = 0.5 |
| 17 |
16 | 18 |
17 class SurfaceStatsCollector(object): | 19 class SurfaceStatsCollector(object): |
18 """Collects surface stats for a SurfaceView from the output of SurfaceFlinger. | 20 """Collects surface stats for a SurfaceView from the output of SurfaceFlinger. |
19 | 21 |
20 Args: | 22 Args: |
21 adb: the adb connection to use. | 23 adb: the adb connection to use. |
22 """ | 24 """ |
23 class Result(object): | 25 class Result(object): |
24 def __init__(self, name, value, unit): | 26 def __init__(self, name, value, unit): |
25 self.name = name | 27 self.name = name |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 def _GetEmptyResults(self): | 74 def _GetEmptyResults(self): |
73 return [ | 75 return [ |
74 SurfaceStatsCollector.Result('refresh_period', None, 'seconds'), | 76 SurfaceStatsCollector.Result('refresh_period', None, 'seconds'), |
75 SurfaceStatsCollector.Result('jank_count', None, 'janks'), | 77 SurfaceStatsCollector.Result('jank_count', None, 'janks'), |
76 SurfaceStatsCollector.Result('max_frame_delay', None, 'vsyncs'), | 78 SurfaceStatsCollector.Result('max_frame_delay', None, 'vsyncs'), |
77 SurfaceStatsCollector.Result('frame_lengths', None, 'vsyncs'), | 79 SurfaceStatsCollector.Result('frame_lengths', None, 'vsyncs'), |
78 SurfaceStatsCollector.Result('avg_surface_fps', None, 'fps') | 80 SurfaceStatsCollector.Result('avg_surface_fps', None, 'fps') |
79 ] | 81 ] |
80 | 82 |
81 @staticmethod | 83 @staticmethod |
82 def _GetNormalizedDeltas(data, refresh_period): | 84 def _GetNormalizedDeltas(data, refresh_period, min_normalized_delta=None): |
83 deltas = [t2 - t1 for t1, t2 in zip(data, data[1:])] | 85 deltas = [t2 - t1 for t1, t2 in zip(data, data[1:])] |
| 86 if min_normalized_delta != None: |
| 87 deltas = filter(lambda d: d / refresh_period >= min_normalized_delta, |
| 88 deltas) |
84 return (deltas, [delta / refresh_period for delta in deltas]) | 89 return (deltas, [delta / refresh_period for delta in deltas]) |
85 | 90 |
86 @staticmethod | 91 @staticmethod |
87 def _CalculateResults(refresh_period, timestamps, result_suffix): | 92 def _CalculateResults(refresh_period, timestamps, result_suffix): |
88 """Returns a list of SurfaceStatsCollector.Result.""" | 93 """Returns a list of SurfaceStatsCollector.Result.""" |
89 frame_count = len(timestamps) | 94 frame_count = len(timestamps) |
90 seconds = timestamps[-1] - timestamps[0] | 95 seconds = timestamps[-1] - timestamps[0] |
91 | 96 |
92 frame_lengths, normalized_frame_lengths = \ | 97 frame_lengths, normalized_frame_lengths = \ |
93 SurfaceStatsCollector._GetNormalizedDeltas(timestamps, refresh_period) | 98 SurfaceStatsCollector._GetNormalizedDeltas( |
| 99 timestamps, refresh_period, _MIN_NORMALIZED_FRAME_LENGTH) |
| 100 if len(frame_lengths) < frame_count - 1: |
| 101 logging.warning('Skipping frame lengths that are too short.') |
| 102 frame_count = len(frame_lengths) + 1 |
| 103 if len(frame_lengths) == 0: |
| 104 raise Exception('No valid frames lengths found.') |
94 length_changes, normalized_changes = \ | 105 length_changes, normalized_changes = \ |
95 SurfaceStatsCollector._GetNormalizedDeltas( | 106 SurfaceStatsCollector._GetNormalizedDeltas( |
96 frame_lengths, refresh_period) | 107 frame_lengths, refresh_period) |
97 jankiness = [max(0, round(change)) for change in normalized_changes] | 108 jankiness = [max(0, round(change)) for change in normalized_changes] |
98 pause_threshold = 20 | 109 pause_threshold = 20 |
99 jank_count = sum(1 for change in jankiness | 110 jank_count = sum(1 for change in jankiness |
100 if change > 0 and change < pause_threshold) | 111 if change > 0 and change < pause_threshold) |
101 return [ | 112 return [ |
102 SurfaceStatsCollector.Result( | 113 SurfaceStatsCollector.Result( |
103 'avg_surface_fps' + result_suffix, | 114 'avg_surface_fps' + result_suffix, |
104 int(round(frame_count / seconds)), 'fps'), | 115 int(round((frame_count - 1) / seconds)), 'fps'), |
105 SurfaceStatsCollector.Result( | 116 SurfaceStatsCollector.Result( |
106 'jank_count' + result_suffix, jank_count, 'janks'), | 117 'jank_count' + result_suffix, jank_count, 'janks'), |
107 SurfaceStatsCollector.Result( | 118 SurfaceStatsCollector.Result( |
108 'max_frame_delay' + result_suffix, | 119 'max_frame_delay' + result_suffix, |
109 round(max(normalized_frame_lengths)), | 120 round(max(normalized_frame_lengths)), |
110 'vsyncs'), | 121 'vsyncs'), |
111 SurfaceStatsCollector.Result( | 122 SurfaceStatsCollector.Result( |
112 'frame_lengths' + result_suffix, normalized_frame_lengths, | 123 'frame_lengths' + result_suffix, normalized_frame_lengths, |
113 'vsyncs'), | 124 'vsyncs'), |
114 ] | 125 ] |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 try: | 298 try: |
288 cur_surface = int(match.group(1), 16) | 299 cur_surface = int(match.group(1), 16) |
289 except Exception: | 300 except Exception: |
290 logging.error('Failed to parse current surface from ' + match.group(1)) | 301 logging.error('Failed to parse current surface from ' + match.group(1)) |
291 else: | 302 else: |
292 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) | 303 logging.warning('Failed to call SurfaceFlinger surface ' + results[0]) |
293 return { | 304 return { |
294 'page_flip_count': cur_surface, | 305 'page_flip_count': cur_surface, |
295 'timestamp': datetime.datetime.now(), | 306 'timestamp': datetime.datetime.now(), |
296 } | 307 } |
OLD | NEW |