1 # Copyright (c) 2011 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 5 import logging, math, time 6 7 from autotest_lib.client.bin import test 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.cros import power_status, rtc, sys_power 10 11 class power_Standby(test.test): 12 """Measure Standby(S3) power test.""" 13 version = 1 14 _percent_min_charge = 0.1 15 _min_sample_hours = 0.1 16 17 def run_once(self, test_hours=None, sample_hours=None, 18 percent_initial_charge_min=0.2, max_milliwatts_standby=None): 19 20 if test_hours <= sample_hours: 21 raise error.TestFail("Test hours must be greater than sample hours") 22 23 # If we're measuring <= 6min of S3 then the S0 time is not negligible. 24 # Note, reasonable rule of thumb is S0 idle is ~10-20 times S3 power. 25 if sample_hours < self._min_sample_hours: 26 raise error.TestFail("Must suspend more than %.2f hours" % \ 27 sample_hours) 28 29 # Query initial power status 30 power_stats = power_status.get_status() 31 power_stats.assert_battery_state(percent_initial_charge_min) 32 charge_start = power_stats.battery[0].charge_now 33 voltage_start = power_stats.battery[0].voltage_now 34 35 max_hours = charge_start * voltage_start / \ 36 (max_milliwatts_standby / 1000) 37 if max_hours < test_hours: 38 raise error.TestFail('Battery not charged adequately for test') 39 40 elapsed_hours = 0 41 42 while elapsed_hours < test_hours: 43 charge_before = power_stats.battery[0].charge_now 44 before_suspend_secs = rtc.get_seconds() 45 sys_power.do_suspend(sample_hours * 3600) 46 after_suspend_secs = rtc.get_seconds() 47 48 power_stats.refresh() 49 if power_stats.percent_current_charge() < self._percent_min_charge: 50 logging.warning("Battery percent = %.2f%%. Too low to continue") 51 break 52 53 # check that the RTC slept the correct amount of time as there could 54 # potentially be another wake source that would spoil the test. 55 actual_hours = (after_suspend_secs - before_suspend_secs) / 3600.0 56 logging.debug("actual_hours = %.4f", actual_hours) 57 percent_diff = math.fabs((actual_hours - sample_hours) / 58 ((actual_hours + sample_hours) / 2) * 100) 59 if percent_diff > 2: 60 err_str = "Requested S3 time and actual varied by %.2f%%." \ 61 % percent_diff 62 raise error.TestFail(err_str) 63 64 # Check resulting charge consumption 65 charge_used = charge_before - power_stats.battery[0].charge_now 66 logging.debug("charge_used = %.6f", charge_used) 67 68 elapsed_hours += actual_hours 69 logging.debug("elapsed_hours = %.4f", elapsed_hours) 70 71 charge_end = power_stats.battery[0].charge_now 72 voltage_end = power_stats.battery[0].voltage_now 73 standby_hours = power_stats.battery[0].charge_full_design / \ 74 (charge_start - charge_end) * elapsed_hours 75 energy_used = charge_start * voltage_start - charge_end * voltage_end 76 if energy_used <= 0: 77 raise error.TestError("Energy used reading is suspect.") 78 standby_milliwatts = energy_used / elapsed_hours * 1000 79 80 results = {} 81 results['milliwatts_standby_power'] = standby_milliwatts 82 results['hours_standby_time'] = standby_hours 83 self.write_perf_keyval(results) 84 85 # need to sleep for some time to allow network connection to return 86 time.sleep(10) 87