/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

  1. # Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Utilities for iotop/top style profiling for android."""
  5. import collections
  6. import json
  7. import os
  8. import subprocess
  9. import sys
  10. import urllib
  11. import constants
  12. import io_stats_parser
  13. class DeviceStatsMonitor(object):
  14. """Class for collecting device stats such as IO/CPU usage.
  15. Args:
  16. adb: Instance of AndroidComannds.
  17. hz: Frequency at which to sample device stats.
  18. """
  19. DEVICE_PATH = constants.TEST_EXECUTABLE_DIR + '/device_stats_monitor'
  20. PROFILE_PATH = (constants.DEVICE_PERF_OUTPUT_DIR +
  21. '/device_stats_monitor.profile')
  22. RESULT_VIEWER_PATH = os.path.abspath(os.path.join(
  23. os.path.dirname(os.path.realpath(__file__)), 'device_stats_monitor.html'))
  24. def __init__(self, adb, hz, build_type):
  25. self._adb = adb
  26. host_path = os.path.abspath(os.path.join(
  27. constants.CHROME_DIR, 'out', build_type, 'device_stats_monitor'))
  28. self._adb.PushIfNeeded(host_path, DeviceStatsMonitor.DEVICE_PATH)
  29. self._hz = hz
  30. def Start(self):
  31. """Starts device stats monitor on the device."""
  32. self._adb.SetProtectedFileContents(DeviceStatsMonitor.PROFILE_PATH, '')
  33. self._process = subprocess.Popen(
  34. ['adb', 'shell', '%s --hz=%d %s' % (
  35. DeviceStatsMonitor.DEVICE_PATH, self._hz,
  36. DeviceStatsMonitor.PROFILE_PATH)])
  37. def StopAndCollect(self, output_path):
  38. """Stops monitoring and saves results.
  39. Args:
  40. output_path: Path to save results.
  41. Returns:
  42. String of URL to load results in browser.
  43. """
  44. assert self._process
  45. self._adb.KillAll(DeviceStatsMonitor.DEVICE_PATH)
  46. self._process.wait()
  47. profile = self._adb.GetFileContents(DeviceStatsMonitor.PROFILE_PATH)
  48. results = collections.defaultdict(list)
  49. last_io_stats = None
  50. last_cpu_stats = None
  51. for line in profile:
  52. if ' mmcblk0 ' in line:
  53. stats = io_stats_parser.ParseIoStatsLine(line)
  54. if last_io_stats:
  55. results['sectors_read'].append(stats.num_sectors_read -
  56. last_io_stats.num_sectors_read)
  57. results['sectors_written'].append(stats.num_sectors_written -
  58. last_io_stats.num_sectors_written)
  59. last_io_stats = stats
  60. elif line.startswith('cpu '):
  61. stats = self._ParseCpuStatsLine(line)
  62. if last_cpu_stats:
  63. results['user'].append(stats.user - last_cpu_stats.user)
  64. results['nice'].append(stats.nice - last_cpu_stats.nice)
  65. results['system'].append(stats.system - last_cpu_stats.system)
  66. results['idle'].append(stats.idle - last_cpu_stats.idle)
  67. results['iowait'].append(stats.iowait - last_cpu_stats.iowait)
  68. results['irq'].append(stats.irq - last_cpu_stats.irq)
  69. results['softirq'].append(stats.softirq- last_cpu_stats.softirq)
  70. last_cpu_stats = stats
  71. units = {
  72. 'sectors_read': 'sectors',
  73. 'sectors_written': 'sectors',
  74. 'user': 'jiffies',
  75. 'nice': 'jiffies',
  76. 'system': 'jiffies',
  77. 'idle': 'jiffies',
  78. 'iowait': 'jiffies',
  79. 'irq': 'jiffies',
  80. 'softirq': 'jiffies',
  81. }
  82. with open(output_path, 'w') as f:
  83. f.write('display(%d, %s, %s);' % (self._hz, json.dumps(results), units))
  84. return 'file://%s?results=file://%s' % (
  85. DeviceStatsMonitor.RESULT_VIEWER_PATH, urllib.quote(output_path))
  86. @staticmethod
  87. def _ParseCpuStatsLine(line):
  88. """Parses a line of cpu stats into a CpuStats named tuple."""
  89. # Field definitions: http://www.linuxhowtos.org/System/procstat.htm
  90. cpu_stats = collections.namedtuple('CpuStats',
  91. ['device',
  92. 'user',
  93. 'nice',
  94. 'system',
  95. 'idle',
  96. 'iowait',
  97. 'irq',
  98. 'softirq',
  99. ])
  100. fields = line.split()
  101. return cpu_stats._make([fields[0]] + [int(f) for f in fields[1:8]])