Home | History | Annotate | Download | only in android
      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 import android_commands, surface_stats_collector
     17 from pylib.utils import run_tests_helper
     18 
     19 
     20 _FIELD_FORMAT = {
     21   'jank_count (janks)': '%d',
     22   'max_frame_delay (vsyncs)': '%d',
     23   'avg_surface_fps (fps)': '%.2f',
     24   'frame_lengths (vsyncs)': '%.3f',
     25   'refresh_period (seconds)': '%.6f',
     26 }
     27 
     28 
     29 def _MergeResults(results, fields):
     30   merged_results = collections.defaultdict(list)
     31   for result in results:
     32     if ((fields != ['all'] and not result.name in fields) or
     33         result.value is None):
     34       continue
     35     name = '%s (%s)' % (result.name, result.unit)
     36     if isinstance(result.value, list):
     37       value = result.value
     38     else:
     39       value = [result.value]
     40     merged_results[name] += value
     41   for name, values in merged_results.iteritems():
     42     merged_results[name] = sum(values) / float(len(values))
     43   return merged_results
     44 
     45 
     46 def _GetTerminalHeight():
     47   try:
     48     import fcntl, termios, struct
     49   except ImportError:
     50     return 0, 0
     51   height, _, _, _ = struct.unpack('HHHH',
     52       fcntl.ioctl(0, termios.TIOCGWINSZ,
     53           struct.pack('HHHH', 0, 0, 0, 0)))
     54   return height
     55 
     56 
     57 def _PrintColumnTitles(results):
     58   for name in results.keys():
     59     print '%s ' % name,
     60   print
     61   for name in results.keys():
     62     print '%s ' % ('-' * len(name)),
     63   print
     64 
     65 
     66 def _PrintResults(results):
     67   for name, value in results.iteritems():
     68     value = _FIELD_FORMAT.get(name, '%s') % value
     69     print value.rjust(len(name)) + ' ',
     70   print
     71 
     72 
     73 def main(argv):
     74   parser = optparse.OptionParser(usage='Usage: %prog [options]',
     75                                  description=__doc__)
     76   parser.add_option('-v',
     77                     '--verbose',
     78                     dest='verbose_count',
     79                     default=0,
     80                     action='count',
     81                     help='Verbose level (multiple times for more)')
     82   parser.add_option('--device',
     83                     help='Serial number of device we should use.')
     84   parser.add_option('-f',
     85                     '--fields',
     86                     dest='fields',
     87                     default='jank_count,max_frame_delay,avg_surface_fps,'
     88                         'frame_lengths',
     89                     help='Comma separated list of fields to display or "all".')
     90   parser.add_option('-d',
     91                     '--delay',
     92                     dest='delay',
     93                     default=1,
     94                     type='float',
     95                     help='Time in seconds to sleep between updates.')
     96 
     97   options, args = parser.parse_args(argv)
     98   run_tests_helper.SetLogLevel(options.verbose_count)
     99 
    100   adb = android_commands.AndroidCommands(options.device)
    101   collector = surface_stats_collector.SurfaceStatsCollector(adb)
    102   collector.DisableWarningAboutEmptyData()
    103 
    104   fields = options.fields.split(',')
    105   row_count = None
    106 
    107   try:
    108     collector.Start()
    109     while True:
    110       time.sleep(options.delay)
    111       results = collector.SampleResults()
    112       results = _MergeResults(results, fields)
    113 
    114       if not results:
    115         continue
    116 
    117       terminal_height = _GetTerminalHeight()
    118       if row_count is None or (terminal_height and
    119           row_count >= terminal_height - 3):
    120         _PrintColumnTitles(results)
    121         row_count = 0
    122 
    123       _PrintResults(results)
    124       row_count += 1
    125   except KeyboardInterrupt:
    126     sys.exit(0)
    127   finally:
    128     collector.Stop()
    129 
    130 
    131 if __name__ == '__main__':
    132   main(sys.argv)
    133