1# Copyright (c) 2012 The Chromium OS 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
5import logging, time
6
7from autotest_lib.client.bin import test
8from autotest_lib.client.common_lib.cros import chrome
9from autotest_lib.client.cros import service_stopper
10from autotest_lib.client.cros.bluetooth import bluetooth_device_xmlrpc_server
11from autotest_lib.client.cros.power import power_dashboard
12from autotest_lib.client.cros.power import power_rapl
13from autotest_lib.client.cros.power import power_status
14from autotest_lib.client.cros.power import power_utils
15
16
17class power_Idle(test.test):
18    """class for power_Idle test.
19
20    Collects power stats when machine is idle, also compares power stats between
21    when bluetooth adapter is on and off.
22    """
23    version = 1
24
25    def initialize(self):
26        """Perform necessary initialization prior to test run.
27
28        Private Attributes:
29          _backlight: power_utils.Backlight object
30          _services: service_stopper.ServiceStopper object
31        """
32        super(power_Idle, self).initialize()
33        self._backlight = None
34        self._services = service_stopper.ServiceStopper(
35            service_stopper.ServiceStopper.POWER_DRAW_SERVICES)
36        self._services.stop_services()
37
38
39    def warmup(self, warmup_time=60):
40        """Warm up.
41
42        Wait between initialization and run_once for new settings to stabilize.
43        """
44        time.sleep(warmup_time)
45
46
47    def run_once(self, idle_time=120, sleep=10, bt_warmup_time=20):
48        """Collect power stats when bluetooth adapter is on or off.
49
50        """
51        with chrome.Chrome():
52            self._backlight = power_utils.Backlight()
53            self._backlight.set_default()
54
55            t0 = time.time()
56            self._start_time = t0
57            self._psr = power_utils.DisplayPanelSelfRefresh(init_time=t0)
58            self.status = power_status.get_status()
59            self._stats = power_status.StatoMatic()
60
61            measurements = []
62            if not self.status.on_ac():
63                measurements.append(
64                    power_status.SystemPower(self.status.battery_path))
65            if power_utils.has_powercap_support():
66                measurements += power_rapl.create_powercap()
67            elif power_utils.has_rapl_support():
68                measurements += power_rapl.create_rapl()
69            self._plog = power_status.PowerLogger(measurements,
70                                                  seconds_period=sleep)
71            self._tlog = power_status.TempLogger([], seconds_period=sleep)
72            self._plog.start()
73            self._tlog.start()
74
75            for _ in xrange(0, idle_time, sleep):
76                time.sleep(sleep)
77                self.status.refresh()
78            self.status.refresh()
79            self._plog.checkpoint('bluetooth_adapter_off', self._start_time)
80            self._tlog.checkpoint('', self._start_time)
81            self._psr.refresh()
82
83            # Turn on bluetooth adapter.
84            bt_device = bluetooth_device_xmlrpc_server \
85                    .BluetoothDeviceXmlRpcDelegate()
86            # If we cannot start bluetoothd, fail gracefully and still write
87            # data with bluetooth adapter off to file, as we are interested in
88            # just that data too. start_bluetoothd() already logs the error so
89            # not logging any error here.
90            if not bt_device.start_bluetoothd():
91                return
92            if not bt_device.set_powered(True):
93                logging.warning("Cannot turn on bluetooth adapter.")
94                return
95            time.sleep(bt_warmup_time)
96            if not bt_device._is_powered_on():
97                logging.warning("Bluetooth adapter is off.")
98                return
99            t1 = time.time()
100            time.sleep(idle_time)
101            self._plog.checkpoint('bluetooth_adapter_on', t1)
102            bt_device.set_powered(False)
103            bt_device.stop_bluetoothd()
104
105
106    def _publish_chromeperf_dashboard(self, measurements):
107        """Report to chromeperf dashboard."""
108        publish = {key: measurements[key]
109                   for key in measurements.keys() if key.endswith('pwr')}
110
111        for key, values in publish.iteritems():
112            self.output_perf_value(description=key, value=values,
113                units='W', higher_is_better=False, graph='power')
114
115
116    def postprocess_iteration(self):
117        """Write power stats to file.
118
119        """
120        keyvals = self._stats.publish()
121
122        # record the current and max backlight levels
123        self._backlight = power_utils.Backlight()
124        keyvals['level_backlight_max'] = self._backlight.get_max_level()
125        keyvals['level_backlight_current'] = self._backlight.get_level()
126
127        # record battery stats if not on AC
128        if self.status.on_ac():
129            keyvals['b_on_ac'] = 1
130        else:
131            keyvals['b_on_ac'] = 0
132            keyvals['ah_charge_full'] = self.status.battery[0].charge_full
133            keyvals['ah_charge_full_design'] = \
134                                self.status.battery[0].charge_full_design
135            keyvals['ah_charge_now'] = self.status.battery[0].charge_now
136            keyvals['a_current_now'] = self.status.battery[0].current_now
137            keyvals['wh_energy'] = self.status.battery[0].energy
138            keyvals['w_energy_rate'] = self.status.battery[0].energy_rate
139            keyvals['h_remaining_time'] = self.status.battery[0].remaining_time
140            keyvals['v_voltage_min_design'] = \
141                                self.status.battery[0].voltage_min_design
142            keyvals['v_voltage_now'] = self.status.battery[0].voltage_now
143
144        plog_keyvals = self._plog.calc()
145        self._publish_chromeperf_dashboard(plog_keyvals)
146        keyvals.update(plog_keyvals)
147        keyvals.update(self._tlog.calc())
148        keyvals.update(self._psr.get_keyvals())
149        logging.debug("keyvals = %s", keyvals)
150
151        self.write_perf_keyval(keyvals)
152
153        pdash = power_dashboard.PowerLoggerDashboard(
154                self._plog, self.tagged_testname, self.resultsdir)
155        pdash.upload()
156
157
158    def cleanup(self):
159        """Reverse setting change in initialization.
160
161        """
162        if self._backlight:
163            self._backlight.restore()
164        self._services.restore_services()
165        super(power_Idle, self).cleanup()
166