Index: tools/telemetry/telemetry/core/platform/power_monitor/cros_power_monitor.py |
diff --git a/tools/telemetry/telemetry/core/platform/power_monitor/cros_power_monitor.py b/tools/telemetry/telemetry/core/platform/power_monitor/cros_power_monitor.py |
index 9d3573b02f7a659572fd720aee621e019ff43df7..b1d43f5e2fa224df105ff822363a036aba516bd9 100644 |
--- a/tools/telemetry/telemetry/core/platform/power_monitor/cros_power_monitor.py |
+++ b/tools/telemetry/telemetry/core/platform/power_monitor/cros_power_monitor.py |
@@ -6,10 +6,12 @@ import collections |
import re |
from telemetry import decorators |
-from telemetry.core.platform import power_monitor |
+from telemetry.core.platform.power_monitor import cros_sysfs_platform |
+from telemetry.core.platform.power_monitor import sysfs_power_monitor |
+CPU_PATH = '/sys/devices/system/cpu/' |
-class CrosPowerMonitor(power_monitor.PowerMonitor): |
+class CrosPowerMonitor(sysfs_power_monitor.SysfsPowerMonitor): |
"""PowerMonitor that relies on 'power_supply_info' to monitor power |
consumption of a single ChromeOS application. |
""" |
@@ -22,39 +24,30 @@ class CrosPowerMonitor(power_monitor.PowerMonitor): |
Attributes: |
_browser: The browser to monitor. |
_cri: The Chrome interface. |
- _final_stats: The result of 'power_supply_info' after the test. |
- _initial_stats: The result of 'power_supply_info' before the test. |
- _start_time: The time the test started monitoring power. |
+ _initial_power: The result of 'power_supply_info' before the test. |
""" |
- super(CrosPowerMonitor, self).__init__() |
+ super(CrosPowerMonitor, self).__init__( |
+ cros_sysfs_platform.CrosSysfsPlatform(cri)) |
self._browser = None |
self._cri = cri |
- self._final_stats = None |
- self._initial_stats = None |
- self._start_time = None |
+ self._initial_power = None |
@decorators.Cache |
def CanMonitorPower(self): |
return self._IsOnBatteryPower() |
def StartMonitoringPower(self, browser): |
- assert not self._browser, 'Must call StopMonitoringPower().' |
- self._browser = browser |
- # The time on the device is recorded to determine the length of the test. |
- self._start_time = self._browser.cpu_stats['Gpu']['TotalTime'] |
- self._initial_stats = self._cri.RunCmdOnDevice(['power_supply_info'])[0] |
+ super(CrosPowerMonitor, self).StartMonitoringPower(browser) |
+ self._initial_power = self._cri.RunCmdOnDevice(['power_supply_info'])[0] |
def StopMonitoringPower(self): |
- assert self._browser, 'StartMonitoringPower() not called.' |
- try: |
- # The length of the test is used to measure energy consumption. |
- length_h = (self._browser.cpu_stats['Gpu']['TotalTime'] - |
- self._start_time) / (3600 * 10 ** 3) |
- self._final_stats = self._cri.RunCmdOnDevice(['power_supply_info'])[0] |
- return CrosPowerMonitor.ParseSamplingOutput(self._initial_stats, |
- self._final_stats, length_h) |
- finally: |
- self._browser = None |
+ cpu_stats = super(CrosPowerMonitor, self).StopMonitoringPower() |
+ final_power = self._cri.RunCmdOnDevice(['power_supply_info'])[0] |
+ # The length of the test is used to measure energy consumption. |
+ length_h = (self._end_time - self._start_time) / 3600.0 |
+ power_stats = CrosPowerMonitor.ParsePower( |
+ self._initial_power, final_power, length_h) |
+ return CrosPowerMonitor.CombineResults(cpu_stats, power_stats) |
@staticmethod |
def IsOnBatteryPower(status, board): |
@@ -69,7 +62,7 @@ class CrosPowerMonitor(power_monitor.PowerMonitor): |
""" |
on_battery = status['Line Power']['online'] == 'no' |
# Butterfly can incorrectly report AC online for some time after unplug. |
- # Check batter discharge state to confirm. |
+ # Check battery discharge state to confirm. |
if board == 'butterfly': |
on_battery |= status['Battery']['state'] == 'Discharging' |
return on_battery |
@@ -110,10 +103,10 @@ class CrosPowerMonitor(power_monitor.PowerMonitor): |
rv[dev][kname[0]] = result[0][1] |
else: |
rv[dev][result[0][0]] = result[0][1] |
- return rv |
+ return dict(rv) |
@staticmethod |
- def ParseSamplingOutput(initial_stats, final_stats, length_h): |
+ def ParsePower(initial_stats, final_stats, length_h): |
"""Parse output of 'power_supply_info' |
Args: |
@@ -124,25 +117,47 @@ class CrosPowerMonitor(power_monitor.PowerMonitor): |
Returns: |
Dictionary in the format returned by StopMonitoringPower(). |
""" |
- out_dict = {'identifier': 'power_supply_info', 'power_samples_mw': []} |
+ out_dict = {'identifier': 'power_supply_info'} |
+ component_utilization = {} |
initial = CrosPowerMonitor.ParsePowerSupplyInfo(initial_stats) |
final = CrosPowerMonitor.ParsePowerSupplyInfo(final_stats) |
# The charge value reported by 'power_supply_info' is not precise enough to |
# give meaningful results across shorter tests, so average energy rate and |
# the length of the test are used. |
- average_power_mw = (float(initial['Battery']['energy rate']) + |
- float(final['Battery']['energy rate'])) * 10 ** 3 / 2.0 |
- out_dict['power_samples_mw'].append(average_power_mw) |
+ initial_power_mw = float(initial['Battery']['energy rate']) * 10 ** 3 |
+ final_power_mw = float(final['Battery']['energy rate']) * 10 ** 3 |
+ average_power_mw = (initial_power_mw + final_power_mw) / 2.0 |
+ out_dict['power_samples_mw'] = [initial_power_mw, final_power_mw] |
out_dict['energy_consumption_mwh'] = average_power_mw * length_h |
# Duplicating CrOS battery fields where applicable. |
- whole_package = {} |
- whole_package['charge_full'] = float(final['Battery']['full charge']) |
- whole_package['charge_full_design'] = ( |
+ battery = {} |
+ battery['charge_full'] = float(final['Battery']['full charge']) |
+ battery['charge_full_design'] = ( |
float(final['Battery']['full charge design'])) |
- whole_package['charge_now'] = float(final['Battery']['charge']) |
- whole_package['current_now'] = float(final['Battery']['current']) |
- whole_package['energy'] = float(final['Battery']['energy']) |
- whole_package['energy_rate'] = float(final['Battery']['energy rate']) |
- whole_package['voltage_now'] = float(final['Battery']['voltage']) |
- out_dict['component_utilization'] = {'whole_package': whole_package} |
+ battery['charge_now'] = float(final['Battery']['charge']) |
+ battery['current_now'] = float(final['Battery']['current']) |
+ battery['energy'] = float(final['Battery']['energy']) |
+ battery['energy_rate'] = float(final['Battery']['energy rate']) |
+ battery['voltage_now'] = float(final['Battery']['voltage']) |
+ component_utilization['battery'] = battery |
+ out_dict['component_utilization'] = component_utilization |
return out_dict |
+ |
+ @staticmethod |
+ def CombineResults(cpu_stats, power_stats): |
+ """Add frequency and c-state residency data to the power data. |
+ |
+ Args: |
+ cpu_stats: Dictionary of CPU data gathered from SysfsPowerMonitor. |
+ power_stats: Dictionary containing power statistics. |
+ |
+ Returns: |
+ Dictionary in the format returned by StopMonitoringPower. |
+ """ |
+ if not cpu_stats: |
+ return power_stats |
+ comp_util = power_stats['component_utilization'] |
+ # Add CPU stats to power stat dictionary. |
+ for cpu in cpu_stats: |
+ comp_util[cpu] = cpu_stats[cpu] |
+ return power_stats |