1# Copyright 2018 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. 4import logging 5import time 6 7from autotest_lib.client.bin import test 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.cros import service_stopper 10from autotest_lib.client.cros.power import power_dashboard 11from autotest_lib.client.cros.power import power_rapl 12from autotest_lib.client.cros.power import power_status 13from autotest_lib.client.cros.power import power_telemetry_utils 14from autotest_lib.client.cros.power import power_utils 15 16 17class power_Test(test.test): 18 """Optional base class power related tests.""" 19 version = 1 20 21 def initialize(self, seconds_period=20., pdash_note='', 22 force_discharge=False): 23 """Perform necessary initialization prior to power test run. 24 25 @param seconds_period: float of probing interval in seconds. 26 @param pdash_note: note of the current run to send to power dashboard. 27 @param force_discharge: force battery to discharge during the test. 28 29 @var backlight: power_utils.Backlight object. 30 @var keyvals: dictionary of result keyvals. 31 @var status: power_status.SysStat object. 32 33 @var _checkpoint_logger: power_status.CheckpointLogger to track 34 checkpoint data. 35 @var _plog: power_status.PowerLogger object to monitor power. 36 @var _psr: power_utils.DisplayPanelSelfRefresh object to monitor PSR. 37 @var _services: service_stopper.ServiceStopper object. 38 @var _start_time: float of time in seconds since Epoch test started. 39 @var _stats: power_status.StatoMatic object. 40 @var _tlog: power_status.TempLogger object to monitor temperatures. 41 @var _clog: power_status.CPUStatsLogger object to monitor CPU(s) 42 frequencies and c-states. 43 @var _meas_logs: list of power_status.MeasurementLoggers 44 """ 45 super(power_Test, self).initialize() 46 self.backlight = power_utils.Backlight() 47 self.backlight.set_default() 48 self.keyvals = dict() 49 self.status = power_status.get_status() 50 51 self._checkpoint_logger = power_status.CheckpointLogger() 52 self._seconds_period = seconds_period 53 54 measurements = [] 55 56 self._force_discharge = force_discharge 57 if force_discharge: 58 if not self.status.battery: 59 raise error.TestNAError('DUT does not have battery. ' 60 'Could not force discharge.') 61 if not power_utils.charge_control_by_ectool(False): 62 raise error.TestError('Could not run battery force discharge.') 63 64 if force_discharge or not self.status.on_ac(): 65 measurements.append( 66 power_status.SystemPower(self.status.battery_path)) 67 if power_utils.has_powercap_support(): 68 measurements += power_rapl.create_powercap() 69 elif power_utils.has_rapl_support(): 70 measurements += power_rapl.create_rapl() 71 self._plog = power_status.PowerLogger(measurements, 72 seconds_period=seconds_period, 73 checkpoint_logger=self._checkpoint_logger) 74 self._psr = power_utils.DisplayPanelSelfRefresh() 75 self._services = service_stopper.ServiceStopper( 76 service_stopper.ServiceStopper.POWER_DRAW_SERVICES) 77 self._services.stop_services() 78 self._stats = power_status.StatoMatic() 79 80 self._tlog = power_status.TempLogger([], 81 seconds_period=seconds_period, 82 checkpoint_logger=self._checkpoint_logger) 83 self._clog = power_status.CPUStatsLogger(seconds_period=seconds_period, 84 checkpoint_logger=self._checkpoint_logger) 85 86 self._meas_logs = [self._plog, self._tlog, self._clog] 87 88 self._pdash_note = pdash_note 89 90 def warmup(self, warmup_time=30): 91 """Warm up. 92 93 Wait between initialization and run_once for new settings to stabilize. 94 95 @param warmup_time: integer of seconds to warmup. 96 """ 97 time.sleep(warmup_time) 98 99 def start_measurements(self): 100 """Start measurements.""" 101 for log in self._meas_logs: 102 log.start() 103 self._start_time = time.time() 104 if self.status.battery: 105 self._start_energy = self.status.battery.energy 106 power_telemetry_utils.start_measurement() 107 108 def loop_sleep(self, loop, sleep_secs): 109 """Jitter free sleep. 110 111 @param loop: integer of loop (1st is zero). 112 @param sleep_secs: integer of desired sleep seconds. 113 """ 114 next_time = self._start_time + (loop + 1) * sleep_secs 115 time.sleep(next_time - time.time()) 116 117 def checkpoint_measurements(self, name, start_time=None): 118 """Checkpoint measurements. 119 120 @param name: string name of measurement being checkpointed. 121 @param start_time: float of time in seconds since Epoch that 122 measurements being checkpointed began. 123 """ 124 if not start_time: 125 start_time = self._start_time 126 self.status.refresh() 127 self._checkpoint_logger.checkpoint(name, start_time) 128 self._psr.refresh() 129 130 def publish_keyvals(self): 131 """Publish power result keyvals.""" 132 keyvals = self._stats.publish() 133 keyvals['level_backlight_max'] = self.backlight.get_max_level() 134 keyvals['level_backlight_current'] = self.backlight.get_level() 135 136 # record battery stats if not on AC 137 if not self._force_discharge and self.status.on_ac(): 138 keyvals['b_on_ac'] = 1 139 else: 140 keyvals['b_on_ac'] = 0 141 142 if self.status.battery: 143 keyvals['ah_charge_full'] = self.status.battery.charge_full 144 keyvals['ah_charge_full_design'] = \ 145 self.status.battery.charge_full_design 146 keyvals['ah_charge_now'] = self.status.battery.charge_now 147 keyvals['a_current_now'] = self.status.battery.current_now 148 keyvals['wh_energy'] = self.status.battery.energy 149 energy_used = self._start_energy - self.status.battery.energy 150 runtime_minutes = (time.time() - self._start_time) / 60. 151 keyvals['wh_energy_used'] = energy_used 152 keyvals['minutes_tested'] = runtime_minutes 153 if energy_used > 0 and runtime_minutes > 1: 154 keyvals['w_energy_rate'] = energy_used * 60 / runtime_minutes 155 keyvals['v_voltage_min_design'] = \ 156 self.status.battery.voltage_min_design 157 keyvals['v_voltage_now'] = self.status.battery.voltage_now 158 159 for log in self._meas_logs: 160 keyvals.update(log.calc()) 161 keyvals.update(self._psr.get_keyvals()) 162 163 self.keyvals.update(keyvals) 164 165 core_keyvals = power_utils.get_core_keyvals(self.keyvals) 166 self.write_perf_keyval(core_keyvals) 167 168 def publish_dashboard(self): 169 """Report results to chromeperf & power dashboard.""" 170 171 self.publish_keyvals() 172 173 # publish power values 174 for key, values in self.keyvals.iteritems(): 175 if key.endswith('pwr_avg'): 176 self.output_perf_value(description=key, value=values, units='W', 177 higher_is_better=False, graph='power') 178 179 # publish temperature values 180 for key, values in self.keyvals.iteritems(): 181 if key.endswith('temp_avg'): 182 self.output_perf_value(description=key, value=values, units='C', 183 higher_is_better=False, graph='temperature') 184 185 # publish to power dashboard 186 pdash = power_dashboard.PowerLoggerDashboard( 187 self._plog, self.tagged_testname, self.resultsdir, 188 note=self._pdash_note) 189 pdash.upload() 190 cdash = power_dashboard.CPUStatsLoggerDashboard( 191 self._clog, self.tagged_testname, self.resultsdir, 192 note=self._pdash_note) 193 cdash.upload() 194 tdash = power_dashboard.TempLoggerDashboard( 195 self._tlog, self.tagged_testname, self.resultsdir, 196 note=self._pdash_note) 197 tdash.upload() 198 199 def _save_results(self): 200 """Save results of each logger in resultsdir.""" 201 for log in self._meas_logs: 202 log.save_results(self.resultsdir) 203 self._checkpoint_logger.save_checkpoint_data(self.resultsdir) 204 205 def postprocess_iteration(self): 206 """Write keyval and send data to dashboard.""" 207 power_telemetry_utils.end_measurement() 208 self.status.refresh() 209 for log in self._meas_logs: 210 log.done = True 211 super(power_Test, self).postprocess_iteration() 212 self.publish_dashboard() 213 self._save_results() 214 215 def cleanup(self): 216 """Reverse setting change in initialization.""" 217 if self._force_discharge: 218 if not power_utils.charge_control_by_ectool(True): 219 logging.warn('Can not restore from force discharge.') 220 if self.backlight: 221 self.backlight.restore() 222 self._services.restore_services() 223 super(power_Test, self).cleanup() 224