Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / platform / power_monitor / cros_power_monitor.py
1 # Copyright 2014 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
5 import collections
6 import re
7
8 from telemetry import decorators
9 from telemetry.core.platform.power_monitor import sysfs_power_monitor
10
11
12 class CrosPowerMonitor(sysfs_power_monitor.SysfsPowerMonitor):
13   """PowerMonitor that relies on 'power_supply_info' to monitor power
14   consumption of a single ChromeOS application.
15   """
16   def __init__(self, platform_backend):
17     """Constructor.
18
19     Args:
20         platform_backend: A LinuxBasedPlatformBackend object.
21
22     Attributes:
23         _initial_power: The result of 'power_supply_info' before the test.
24         _start_time: The epoch time at which the test starts executing.
25     """
26     super(CrosPowerMonitor, self).__init__(platform_backend)
27     self._initial_power = None
28     self._start_time = None
29
30   @decorators.Cache
31   def CanMonitorPower(self):
32     return super(CrosPowerMonitor, self).CanMonitorPower()
33
34   def StartMonitoringPower(self, browser):
35     super(CrosPowerMonitor, self).StartMonitoringPower(browser)
36     if self._IsOnBatteryPower():
37       sample = self._platform.RunCommand(['power_supply_info;', 'date', '+%s'])
38       self._initial_power, self._start_time = CrosPowerMonitor.SplitSample(
39           sample)
40
41   def StopMonitoringPower(self):
42     cpu_stats = super(CrosPowerMonitor, self).StopMonitoringPower()
43     power_stats = {}
44     if self._IsOnBatteryPower():
45       sample = self._platform.RunCommand(['power_supply_info;', 'date', '+%s'])
46       final_power, end_time = CrosPowerMonitor.SplitSample(sample)
47       # The length of the test is used to measure energy consumption.
48       length_h = (end_time - self._start_time) / 3600.0
49       power_stats = CrosPowerMonitor.ParsePower(self._initial_power,
50                                                 final_power, length_h)
51     return CrosPowerMonitor.CombineResults(cpu_stats, power_stats)
52
53   @staticmethod
54   def SplitSample(sample):
55     """Splits a power and time sample into the two separate values.
56
57     Args:
58         sample: The result of calling 'power_supply_info; date +%s' on the
59             device.
60
61     Returns:
62         A tuple of power sample and epoch time of the sample.
63     """
64     sample = sample.strip()
65     index = sample.rfind('\n')
66     power = sample[:index]
67     time = sample[index + 1:]
68     return power, int(time)
69
70   @staticmethod
71   def IsOnBatteryPower(status, board):
72     """Determines if the devices is being charged.
73
74     Args:
75         status: The parsed result of 'power_supply_info'
76         board: The name of the board running the test.
77
78     Returns:
79         True if the device is on battery power; False otherwise.
80     """
81     on_battery = status['Line Power']['online'] == 'no'
82     # Butterfly can incorrectly report AC online for some time after unplug.
83     # Check battery discharge state to confirm.
84     if board == 'butterfly':
85       on_battery |= status['Battery']['state'] == 'Discharging'
86     return on_battery
87
88   def _IsOnBatteryPower(self):
89     """Determines if the device is being charged.
90
91     Returns:
92         True if the device is on battery power; False otherwise.
93     """
94     status = CrosPowerMonitor.ParsePowerSupplyInfo(
95         self._platform.RunCommand(['power_supply_info']))
96     board_data = self._platform.RunCommand(['cat', '/etc/lsb-release'])
97     board = re.search('BOARD=(.*)', board_data).group(1)
98     return CrosPowerMonitor.IsOnBatteryPower(status, board)
99
100   @staticmethod
101   def ParsePowerSupplyInfo(sample):
102     """Parses 'power_supply_info' command output.
103
104     Args:
105         sample: The output of 'power_supply_info'
106
107     Returns:
108         Dictionary containing all fields from 'power_supply_info'
109     """
110     rv = collections.defaultdict(dict)
111     dev = None
112     for ln in sample.splitlines():
113       result = re.findall(r'^Device:\s+(.*)', ln)
114       if result:
115         dev = result[0]
116         continue
117       result = re.findall(r'\s+(.+):\s+(.+)', ln)
118       if result and dev:
119         kname = re.findall(r'(.*)\s+\(\w+\)', result[0][0])
120         if kname:
121           rv[dev][kname[0]] = result[0][1]
122         else:
123           rv[dev][result[0][0]] = result[0][1]
124     return dict(rv)
125
126   @staticmethod
127   def ParsePower(initial_stats, final_stats, length_h):
128     """Parse output of 'power_supply_info'
129
130     Args:
131         initial_stats: The output of 'power_supply_info' before the test.
132         final_stats: The output of 'power_supply_info' after the test.
133         length_h: The length of the test in hours.
134
135     Returns:
136         Dictionary in the format returned by StopMonitoringPower().
137     """
138     out_dict = {'identifier': 'power_supply_info'}
139     component_utilization = {}
140     initial = CrosPowerMonitor.ParsePowerSupplyInfo(initial_stats)
141     final = CrosPowerMonitor.ParsePowerSupplyInfo(final_stats)
142     # The charge value reported by 'power_supply_info' is not precise enough to
143     # give meaningful results across shorter tests, so average energy rate and
144     # the length of the test are used.
145     initial_power_mw = float(initial['Battery']['energy rate']) * 10 ** 3
146     final_power_mw = float(final['Battery']['energy rate']) * 10 ** 3
147     average_power_mw = (initial_power_mw + final_power_mw) / 2.0
148     out_dict['power_samples_mw'] = [initial_power_mw, final_power_mw]
149     out_dict['energy_consumption_mwh'] = average_power_mw * length_h
150     # Duplicating CrOS battery fields where applicable.
151     battery = {}
152     battery['charge_full'] = float(final['Battery']['full charge'])
153     battery['charge_full_design'] = (
154         float(final['Battery']['full charge design']))
155     battery['charge_now'] = float(final['Battery']['charge'])
156     battery['current_now'] = float(final['Battery']['current'])
157     battery['energy'] = float(final['Battery']['energy'])
158     battery['energy_rate'] = float(final['Battery']['energy rate'])
159     battery['voltage_now'] = float(final['Battery']['voltage'])
160     component_utilization['battery'] = battery
161     out_dict['component_utilization'] = component_utilization
162     return out_dict