/chromium-webcl/src/build/android/pylib/device_stats_monitor.py
https://bitbucket.org/peixuan/chromium_r197479_base · Python · 116 lines · 83 code · 12 blank · 21 comment · 7 complexity · c8fe93d7199caa8d1833c89e00657b5c MD5 · raw file
- # Copyright (c) 2012 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Utilities for iotop/top style profiling for android."""
- import collections
- import json
- import os
- import subprocess
- import sys
- import urllib
- import constants
- import io_stats_parser
- class DeviceStatsMonitor(object):
- """Class for collecting device stats such as IO/CPU usage.
- Args:
- adb: Instance of AndroidComannds.
- hz: Frequency at which to sample device stats.
- """
- DEVICE_PATH = constants.TEST_EXECUTABLE_DIR + '/device_stats_monitor'
- PROFILE_PATH = (constants.DEVICE_PERF_OUTPUT_DIR +
- '/device_stats_monitor.profile')
- RESULT_VIEWER_PATH = os.path.abspath(os.path.join(
- os.path.dirname(os.path.realpath(__file__)), 'device_stats_monitor.html'))
- def __init__(self, adb, hz, build_type):
- self._adb = adb
- host_path = os.path.abspath(os.path.join(
- constants.CHROME_DIR, 'out', build_type, 'device_stats_monitor'))
- self._adb.PushIfNeeded(host_path, DeviceStatsMonitor.DEVICE_PATH)
- self._hz = hz
- def Start(self):
- """Starts device stats monitor on the device."""
- self._adb.SetProtectedFileContents(DeviceStatsMonitor.PROFILE_PATH, '')
- self._process = subprocess.Popen(
- ['adb', 'shell', '%s --hz=%d %s' % (
- DeviceStatsMonitor.DEVICE_PATH, self._hz,
- DeviceStatsMonitor.PROFILE_PATH)])
- def StopAndCollect(self, output_path):
- """Stops monitoring and saves results.
- Args:
- output_path: Path to save results.
- Returns:
- String of URL to load results in browser.
- """
- assert self._process
- self._adb.KillAll(DeviceStatsMonitor.DEVICE_PATH)
- self._process.wait()
- profile = self._adb.GetFileContents(DeviceStatsMonitor.PROFILE_PATH)
- results = collections.defaultdict(list)
- last_io_stats = None
- last_cpu_stats = None
- for line in profile:
- if ' mmcblk0 ' in line:
- stats = io_stats_parser.ParseIoStatsLine(line)
- if last_io_stats:
- results['sectors_read'].append(stats.num_sectors_read -
- last_io_stats.num_sectors_read)
- results['sectors_written'].append(stats.num_sectors_written -
- last_io_stats.num_sectors_written)
- last_io_stats = stats
- elif line.startswith('cpu '):
- stats = self._ParseCpuStatsLine(line)
- if last_cpu_stats:
- results['user'].append(stats.user - last_cpu_stats.user)
- results['nice'].append(stats.nice - last_cpu_stats.nice)
- results['system'].append(stats.system - last_cpu_stats.system)
- results['idle'].append(stats.idle - last_cpu_stats.idle)
- results['iowait'].append(stats.iowait - last_cpu_stats.iowait)
- results['irq'].append(stats.irq - last_cpu_stats.irq)
- results['softirq'].append(stats.softirq- last_cpu_stats.softirq)
- last_cpu_stats = stats
- units = {
- 'sectors_read': 'sectors',
- 'sectors_written': 'sectors',
- 'user': 'jiffies',
- 'nice': 'jiffies',
- 'system': 'jiffies',
- 'idle': 'jiffies',
- 'iowait': 'jiffies',
- 'irq': 'jiffies',
- 'softirq': 'jiffies',
- }
- with open(output_path, 'w') as f:
- f.write('display(%d, %s, %s);' % (self._hz, json.dumps(results), units))
- return 'file://%s?results=file://%s' % (
- DeviceStatsMonitor.RESULT_VIEWER_PATH, urllib.quote(output_path))
- @staticmethod
- def _ParseCpuStatsLine(line):
- """Parses a line of cpu stats into a CpuStats named tuple."""
- # Field definitions: http://www.linuxhowtos.org/System/procstat.htm
- cpu_stats = collections.namedtuple('CpuStats',
- ['device',
- 'user',
- 'nice',
- 'system',
- 'idle',
- 'iowait',
- 'irq',
- 'softirq',
- ])
- fields = line.split()
- return cpu_stats._make([fields[0]] + [int(f) for f in fields[1:8]])