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]])