media/webrtc/trunk/build/android/pylib/device_stats_monitor.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/webrtc/trunk/build/android/pylib/device_stats_monitor.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,116 @@
     1.4 +# Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.5 +# Use of this source code is governed by a BSD-style license that can be
     1.6 +# found in the LICENSE file.
     1.7 +
     1.8 +"""Utilities for iotop/top style profiling for android."""
     1.9 +
    1.10 +import collections
    1.11 +import json
    1.12 +import os
    1.13 +import subprocess
    1.14 +import sys
    1.15 +import urllib
    1.16 +
    1.17 +import constants
    1.18 +import io_stats_parser
    1.19 +
    1.20 +
    1.21 +class DeviceStatsMonitor(object):
    1.22 +  """Class for collecting device stats such as IO/CPU usage.
    1.23 +
    1.24 +  Args:
    1.25 +      adb: Instance of AndroidComannds.
    1.26 +      hz: Frequency at which to sample device stats.
    1.27 +  """
    1.28 +
    1.29 +  DEVICE_PATH = constants.TEST_EXECUTABLE_DIR + '/device_stats_monitor'
    1.30 +  PROFILE_PATH = (constants.DEVICE_PERF_OUTPUT_DIR +
    1.31 +      '/device_stats_monitor.profile')
    1.32 +  RESULT_VIEWER_PATH = os.path.abspath(os.path.join(
    1.33 +      os.path.dirname(os.path.realpath(__file__)), 'device_stats_monitor.html'))
    1.34 +
    1.35 +  def __init__(self, adb, hz, build_type):
    1.36 +    self._adb = adb
    1.37 +    host_path = os.path.abspath(os.path.join(
    1.38 +        constants.CHROME_DIR, 'out', build_type, 'device_stats_monitor'))
    1.39 +    self._adb.PushIfNeeded(host_path, DeviceStatsMonitor.DEVICE_PATH)
    1.40 +    self._hz = hz
    1.41 +
    1.42 +  def Start(self):
    1.43 +    """Starts device stats monitor on the device."""
    1.44 +    self._adb.SetFileContents(DeviceStatsMonitor.PROFILE_PATH, '')
    1.45 +    self._process = subprocess.Popen(
    1.46 +        ['adb', 'shell', '%s --hz=%d %s' % (
    1.47 +            DeviceStatsMonitor.DEVICE_PATH, self._hz,
    1.48 +            DeviceStatsMonitor.PROFILE_PATH)])
    1.49 +
    1.50 +  def StopAndCollect(self, output_path):
    1.51 +    """Stops monitoring and saves results.
    1.52 +
    1.53 +    Args:
    1.54 +      output_path: Path to save results.
    1.55 +
    1.56 +    Returns:
    1.57 +      String of URL to load results in browser.
    1.58 +    """
    1.59 +    assert self._process
    1.60 +    self._adb.KillAll(DeviceStatsMonitor.DEVICE_PATH)
    1.61 +    self._process.wait()
    1.62 +    profile = self._adb.GetFileContents(DeviceStatsMonitor.PROFILE_PATH)
    1.63 +
    1.64 +    results = collections.defaultdict(list)
    1.65 +    last_io_stats = None
    1.66 +    last_cpu_stats = None
    1.67 +    for line in profile:
    1.68 +      if ' mmcblk0 ' in line:
    1.69 +        stats = io_stats_parser.ParseIoStatsLine(line)
    1.70 +        if last_io_stats:
    1.71 +          results['sectors_read'].append(stats.num_sectors_read -
    1.72 +                                         last_io_stats.num_sectors_read)
    1.73 +          results['sectors_written'].append(stats.num_sectors_written -
    1.74 +                                            last_io_stats.num_sectors_written)
    1.75 +        last_io_stats = stats
    1.76 +      elif line.startswith('cpu '):
    1.77 +        stats = self._ParseCpuStatsLine(line)
    1.78 +        if last_cpu_stats:
    1.79 +          results['user'].append(stats.user - last_cpu_stats.user)
    1.80 +          results['nice'].append(stats.nice - last_cpu_stats.nice)
    1.81 +          results['system'].append(stats.system - last_cpu_stats.system)
    1.82 +          results['idle'].append(stats.idle - last_cpu_stats.idle)
    1.83 +          results['iowait'].append(stats.iowait - last_cpu_stats.iowait)
    1.84 +          results['irq'].append(stats.irq - last_cpu_stats.irq)
    1.85 +          results['softirq'].append(stats.softirq- last_cpu_stats.softirq)
    1.86 +        last_cpu_stats = stats
    1.87 +    units = {
    1.88 +      'sectors_read': 'sectors',
    1.89 +      'sectors_written': 'sectors',
    1.90 +      'user': 'jiffies',
    1.91 +      'nice': 'jiffies',
    1.92 +      'system': 'jiffies',
    1.93 +      'idle': 'jiffies',
    1.94 +      'iowait': 'jiffies',
    1.95 +      'irq': 'jiffies',
    1.96 +      'softirq': 'jiffies',
    1.97 +    }
    1.98 +    with open(output_path, 'w') as f:
    1.99 +      f.write('display(%d, %s, %s);' % (self._hz, json.dumps(results), units))
   1.100 +    return 'file://%s?results=file://%s' % (
   1.101 +        DeviceStatsMonitor.RESULT_VIEWER_PATH, urllib.quote(output_path))
   1.102 +
   1.103 +
   1.104 +  @staticmethod
   1.105 +  def _ParseCpuStatsLine(line):
   1.106 +    """Parses a line of cpu stats into a CpuStats named tuple."""
   1.107 +    # Field definitions: http://www.linuxhowtos.org/System/procstat.htm
   1.108 +    cpu_stats = collections.namedtuple('CpuStats',
   1.109 +                                       ['device',
   1.110 +                                        'user',
   1.111 +                                        'nice',
   1.112 +                                        'system',
   1.113 +                                        'idle',
   1.114 +                                        'iowait',
   1.115 +                                        'irq',
   1.116 +                                        'softirq',
   1.117 +                                       ])
   1.118 +    fields = line.split()
   1.119 +    return cpu_stats._make([fields[0]] + [int(f) for f in fields[1:8]])

mercurial