244 lines
10 KiB
Python
244 lines
10 KiB
Python
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import logging, time
|
|
from autotest_lib.client.bin import test, utils
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.cros.graphics import graphics_utils
|
|
from autotest_lib.client.cros.power import power_status, power_utils
|
|
|
|
|
|
def get_num_outputs_on():
|
|
"""
|
|
Retrieves the number of connected outputs that are on.
|
|
@return: integer value of number of connected outputs that are on.
|
|
"""
|
|
|
|
return graphics_utils.get_num_outputs_on();
|
|
|
|
class power_BacklightControl(test.test):
|
|
version = 1
|
|
# Minimum number of steps expected between min and max brightness levels.
|
|
_min_num_steps = 4
|
|
# Minimum required percentage change in energy rate between transitions
|
|
# (max -> min, min-> off)
|
|
_energy_rate_change_threshold_percent = 5
|
|
|
|
|
|
def initialize(self):
|
|
"""Perform necessary initialization prior to test run.
|
|
|
|
Private Attributes:
|
|
_backlight: power_utils.Backlight object
|
|
"""
|
|
super(power_BacklightControl, self).initialize()
|
|
self._backlight = None
|
|
|
|
|
|
def run_once(self):
|
|
# Require that this test be run on battery with at least 5% charge
|
|
status = power_status.get_status()
|
|
status.assert_battery_state(5)
|
|
|
|
prefs = { 'has_ambient_light_sensor' : 0,
|
|
'ignore_external_policy' : 1,
|
|
'plugged_dim_ms' : 7200000,
|
|
'plugged_off_ms' : 9000000,
|
|
'plugged_suspend_ms' : 18000000,
|
|
'unplugged_dim_ms' : 7200000,
|
|
'unplugged_off_ms' : 9000000,
|
|
'unplugged_suspend_ms' : 18000000 }
|
|
self._pref_change = power_utils.PowerPrefChanger(prefs)
|
|
|
|
keyvals = {}
|
|
num_errors = 0
|
|
|
|
# These are the expected ratios of energy rate between max, min, and off
|
|
# (zero) brightness levels. e.g. when changing from max to min, the
|
|
# energy rate must become <= (max_energy_rate * max_to_min_factor).
|
|
max_to_min_factor = \
|
|
1.0 - self._energy_rate_change_threshold_percent / 100.0
|
|
min_to_off_factor = \
|
|
1.0 - self._energy_rate_change_threshold_percent / 100.0
|
|
off_to_max_factor = 1.0 / (max_to_min_factor * min_to_off_factor)
|
|
|
|
# Determine the number of outputs that are on.
|
|
starting_num_outputs_on = get_num_outputs_on()
|
|
if starting_num_outputs_on == 0:
|
|
raise error.TestFail('At least one display output must be on.')
|
|
keyvals['starting_num_outputs_on'] = starting_num_outputs_on
|
|
|
|
self._backlight = power_utils.Backlight()
|
|
keyvals['max_brightness'] = self._backlight.get_max_level()
|
|
if keyvals['max_brightness'] <= self._min_num_steps:
|
|
raise error.TestFail('Must have at least %d backlight levels' %
|
|
(self._min_num_steps + 1))
|
|
|
|
keyvals['initial_brightness'] = self._backlight.get_level()
|
|
|
|
self._wait_for_stable_energy_rate()
|
|
keyvals['initial_power_w'] = self._get_current_energy_rate()
|
|
|
|
self._backlight_controller = power_utils.BacklightController()
|
|
self._backlight_controller.set_brightness_to_max()
|
|
|
|
current_brightness = \
|
|
utils.wait_for_value(self._backlight.get_level,
|
|
max_threshold=keyvals['max_brightness'])
|
|
if current_brightness != keyvals['max_brightness']:
|
|
num_errors += 1
|
|
logging.error(('Failed to increase brightness to max, ' + \
|
|
'brightness is %d.') % current_brightness)
|
|
else:
|
|
self._wait_for_stable_energy_rate()
|
|
keyvals['max_brightness_power_w'] = self._get_current_energy_rate()
|
|
|
|
# Set brightness to minimum without going to zero.
|
|
# Note that we don't know what the minimum brightness is, so just set
|
|
# min_threshold=0 to use the timeout to wait for the brightness to
|
|
# settle.
|
|
self._backlight_controller.set_brightness_to_min()
|
|
current_brightness = utils.wait_for_value(
|
|
self._backlight.get_level,
|
|
min_threshold=(keyvals['max_brightness'] / 2 - 1))
|
|
if current_brightness >= keyvals['max_brightness'] / 2 or \
|
|
current_brightness == 0:
|
|
num_errors += 1
|
|
logging.error('Brightness is not at minimum non-zero level: %d' %
|
|
current_brightness)
|
|
else:
|
|
self._wait_for_stable_energy_rate()
|
|
keyvals['min_brightness_power_w'] = self._get_current_energy_rate()
|
|
|
|
# Turn off the screen by decreasing brightness one more time with
|
|
# allow_off=True.
|
|
self._backlight_controller.decrease_brightness(True)
|
|
current_brightness = utils.wait_for_value(
|
|
self._backlight.get_level, min_threshold=0)
|
|
if current_brightness != 0:
|
|
num_errors += 1
|
|
logging.error('Brightness is %d, expecting 0.' % current_brightness)
|
|
|
|
# Wait for screen to turn off.
|
|
num_outputs_on = utils.wait_for_value(
|
|
get_num_outputs_on, min_threshold=(starting_num_outputs_on - 1))
|
|
keyvals['outputs_on_after_screen_off'] = num_outputs_on
|
|
if num_outputs_on >= starting_num_outputs_on:
|
|
num_errors += 1
|
|
logging.error('At least one display must have been turned off. ' + \
|
|
'Number of displays on: %s' % num_outputs_on)
|
|
else:
|
|
self._wait_for_stable_energy_rate()
|
|
keyvals['screen_off_power_w'] = self._get_current_energy_rate()
|
|
|
|
# Set brightness to max.
|
|
self._backlight_controller.set_brightness_to_max()
|
|
current_brightness = utils.wait_for_value(
|
|
self._backlight.get_level, max_threshold=keyvals['max_brightness'])
|
|
if current_brightness != keyvals['max_brightness']:
|
|
num_errors += 1
|
|
logging.error(('Failed to increase brightness to max, ' + \
|
|
'brightness is %d.') % current_brightness)
|
|
|
|
# Verify that the same number of outputs are on as before.
|
|
num_outputs_on = get_num_outputs_on()
|
|
keyvals['outputs_on_at_end'] = num_outputs_on
|
|
if num_outputs_on != starting_num_outputs_on:
|
|
num_errors += 1
|
|
logging.error(('Number of displays turned on should be same as ' + \
|
|
'at start. Number of displays on: %s') %
|
|
num_outputs_on)
|
|
|
|
self._wait_for_stable_energy_rate()
|
|
keyvals['final_power_w'] = self._get_current_energy_rate()
|
|
|
|
# Energy rate must have changed significantly between transitions.
|
|
if 'max_brightness_power_w' in keyvals and \
|
|
'min_brightness_power_w' in keyvals and \
|
|
keyvals['min_brightness_power_w'] >= \
|
|
keyvals['max_brightness_power_w'] * max_to_min_factor:
|
|
num_errors += 1
|
|
logging.error('Power draw did not decrease enough when ' + \
|
|
'brightness was decreased from max to min.')
|
|
|
|
if 'screen_off_power_w' in keyvals and \
|
|
'min_brightness_power_w' in keyvals and \
|
|
keyvals['screen_off_power_w'] >= \
|
|
keyvals['min_brightness_power_w'] * min_to_off_factor:
|
|
num_errors += 1
|
|
logging.error('Power draw did not decrease enough when screen ' + \
|
|
'was turned off.')
|
|
|
|
if num_outputs_on == starting_num_outputs_on and \
|
|
'screen_off_power_w' in keyvals and \
|
|
keyvals['final_power_w'] <= \
|
|
keyvals['screen_off_power_w'] * off_to_max_factor:
|
|
num_errors += 1
|
|
logging.error('Power draw did not increase enough after ' + \
|
|
'turning screen on.')
|
|
|
|
self.write_perf_keyval(keyvals)
|
|
|
|
if num_errors > 0:
|
|
raise error.TestFail('Test failed with %d errors' % num_errors)
|
|
|
|
|
|
def cleanup(self):
|
|
if self._backlight:
|
|
self._backlight.restore()
|
|
super(power_BacklightControl, self).cleanup()
|
|
|
|
|
|
def _get_current_energy_rate(self):
|
|
return power_status.get_status().battery.energy_rate
|
|
|
|
|
|
def _wait_for_stable_energy_rate(self,
|
|
max_variation_percent=5,
|
|
sample_delay_sec=1,
|
|
window_size=10,
|
|
timeout_sec=30):
|
|
"""
|
|
Waits for the energy rate to stablize. Stability criterion:
|
|
The last |window_size| samples of energy rate do not deviate from
|
|
their mean by more than |max_variation_percent|.
|
|
|
|
Arguments:
|
|
max_variation_percent Percentage of allowed deviation from mean
|
|
energy rate to still be considered stable.
|
|
sample_delay_sec Time to wait between each reading of the
|
|
energy rate.
|
|
window_size Number of energy rate samples required to
|
|
measure stability. If there are more
|
|
samples than this amount, use only the last
|
|
|window_size| values.
|
|
timeout_sec If stability has not been attained after
|
|
this long, stop waiting.
|
|
|
|
Return value:
|
|
True if energy rate stabilized before timeout.
|
|
False if timed out waiting for energy rate to stabilize.
|
|
"""
|
|
start_time = time.time()
|
|
samples = []
|
|
max_variation_factor = max_variation_percent / 100.0
|
|
while time.time() - start_time < timeout_sec:
|
|
current_rate = self._get_current_energy_rate()
|
|
|
|
# Remove the oldest value if the list of energy rate samples is at
|
|
# the maximum limit |window_size|, before appending a new value.
|
|
if len(samples) >= window_size:
|
|
samples = samples[1:]
|
|
samples.append(current_rate)
|
|
|
|
mean = sum(samples) / len(samples)
|
|
if len(samples) >= window_size and \
|
|
max(samples) <= mean * (1 + max_variation_factor) and \
|
|
min(samples) >= mean * (1 - max_variation_factor):
|
|
return True
|
|
|
|
time.sleep(sample_delay_sec)
|
|
|
|
return False
|