James Robinson | 646469d | 2014-10-03 15:33:28 -0700 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | """Command line tool for continuously printing Android graphics surface |
| 8 | statistics on the console. |
| 9 | """ |
| 10 | |
| 11 | import collections |
| 12 | import optparse |
| 13 | import sys |
| 14 | import time |
| 15 | |
| 16 | from pylib.device import device_utils |
| 17 | from pylib.perf import surface_stats_collector |
| 18 | from pylib.utils import run_tests_helper |
| 19 | |
| 20 | |
| 21 | _FIELD_FORMAT = { |
| 22 | 'jank_count (janks)': '%d', |
| 23 | 'max_frame_delay (vsyncs)': '%d', |
| 24 | 'avg_surface_fps (fps)': '%.2f', |
| 25 | 'frame_lengths (vsyncs)': '%.3f', |
| 26 | 'refresh_period (seconds)': '%.6f', |
| 27 | } |
| 28 | |
| 29 | |
| 30 | def _MergeResults(results, fields): |
| 31 | merged_results = collections.defaultdict(list) |
| 32 | for result in results: |
| 33 | if ((fields != ['all'] and not result.name in fields) or |
| 34 | result.value is None): |
| 35 | continue |
| 36 | name = '%s (%s)' % (result.name, result.unit) |
| 37 | if isinstance(result.value, list): |
| 38 | value = result.value |
| 39 | else: |
| 40 | value = [result.value] |
| 41 | merged_results[name] += value |
| 42 | for name, values in merged_results.iteritems(): |
| 43 | merged_results[name] = sum(values) / float(len(values)) |
| 44 | return merged_results |
| 45 | |
| 46 | |
| 47 | def _GetTerminalHeight(): |
| 48 | try: |
| 49 | import fcntl, termios, struct |
| 50 | except ImportError: |
| 51 | return 0, 0 |
| 52 | height, _, _, _ = struct.unpack('HHHH', |
| 53 | fcntl.ioctl(0, termios.TIOCGWINSZ, |
| 54 | struct.pack('HHHH', 0, 0, 0, 0))) |
| 55 | return height |
| 56 | |
| 57 | |
| 58 | def _PrintColumnTitles(results): |
| 59 | for name in results.keys(): |
| 60 | print '%s ' % name, |
| 61 | print |
| 62 | for name in results.keys(): |
| 63 | print '%s ' % ('-' * len(name)), |
| 64 | print |
| 65 | |
| 66 | |
| 67 | def _PrintResults(results): |
| 68 | for name, value in results.iteritems(): |
| 69 | value = _FIELD_FORMAT.get(name, '%s') % value |
| 70 | print value.rjust(len(name)) + ' ', |
| 71 | print |
| 72 | |
| 73 | |
| 74 | def main(argv): |
| 75 | parser = optparse.OptionParser(usage='Usage: %prog [options]', |
| 76 | description=__doc__) |
| 77 | parser.add_option('-v', |
| 78 | '--verbose', |
| 79 | dest='verbose_count', |
| 80 | default=0, |
| 81 | action='count', |
| 82 | help='Verbose level (multiple times for more)') |
| 83 | parser.add_option('--device', |
| 84 | help='Serial number of device we should use.') |
| 85 | parser.add_option('-f', |
| 86 | '--fields', |
| 87 | dest='fields', |
| 88 | default='jank_count,max_frame_delay,avg_surface_fps,' |
| 89 | 'frame_lengths', |
| 90 | help='Comma separated list of fields to display or "all".') |
| 91 | parser.add_option('-d', |
| 92 | '--delay', |
| 93 | dest='delay', |
| 94 | default=1, |
| 95 | type='float', |
| 96 | help='Time in seconds to sleep between updates.') |
| 97 | |
| 98 | options, _ = parser.parse_args(argv) |
| 99 | run_tests_helper.SetLogLevel(options.verbose_count) |
| 100 | |
| 101 | device = device_utils.DeviceUtils(options.device) |
| 102 | collector = surface_stats_collector.SurfaceStatsCollector(device) |
| 103 | collector.DisableWarningAboutEmptyData() |
| 104 | |
| 105 | fields = options.fields.split(',') |
| 106 | row_count = None |
| 107 | |
| 108 | try: |
| 109 | collector.Start() |
| 110 | while True: |
| 111 | time.sleep(options.delay) |
| 112 | results = collector.SampleResults() |
| 113 | results = _MergeResults(results, fields) |
| 114 | |
| 115 | if not results: |
| 116 | continue |
| 117 | |
| 118 | terminal_height = _GetTerminalHeight() |
| 119 | if row_count is None or (terminal_height and |
| 120 | row_count >= terminal_height - 3): |
| 121 | _PrintColumnTitles(results) |
| 122 | row_count = 0 |
| 123 | |
| 124 | _PrintResults(results) |
| 125 | row_count += 1 |
| 126 | except KeyboardInterrupt: |
| 127 | sys.exit(0) |
| 128 | finally: |
| 129 | collector.Stop() |
| 130 | |
| 131 | |
| 132 | if __name__ == '__main__': |
| 133 | main(sys.argv) |