1650be6d5f895abe5fd9fbca4cf242bdf92443c62Mike Truty# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
26a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda# Use of this source code is governed by a BSD-style license that can be
36a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda# found in the LICENSE file.
46a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
5172ecb7f5a6bbda741799444237a9be4ee21518bEd Bakerimport collections, logging, numpy, os, tempfile, time
60ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehorefrom autotest_lib.client.bin import utils, test
7bee23c2b0ca824c12c39e7a5a4cd4d2a313918b7Eric Lifrom autotest_lib.client.common_lib import error
8172ecb7f5a6bbda741799444237a9be4ee21518bEd Bakerfrom autotest_lib.client.common_lib import file_utils
90ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehorefrom autotest_lib.client.common_lib.cros import chrome
10ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehorefrom autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
11ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehorefrom autotest_lib.client.common_lib.cros.network import xmlrpc_security_types
120ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehorefrom autotest_lib.client.cros import backchannel, httpd
130d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Carusofrom autotest_lib.client.cros import memory_bandwidth_logger
14145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Brochfrom autotest_lib.client.cros import power_rapl, power_status, power_utils
15187240b15fe210be911c5dfc2a414d0780d9be7dTodd Brochfrom autotest_lib.client.cros import service_stopper
1605c4b5d1b1417c4e38f184416b0d0ede23cd4e0aTodd Brochfrom autotest_lib.client.cros.audio import audio_helper
171f89fd2f9f2010e732a87ed3c8f7f25777862c59Christopher Wileyfrom autotest_lib.client.cros.networking import wifi_proxy
18f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Brochfrom telemetry.core import exceptions
199450ad9bc6e5537d93f31bd53f161067fb13a1d5Dale Curtis
209d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nandaparams_dict = {
219d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'test_time_ms': '_mseconds',
229d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'should_scroll': '_should_scroll',
239d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'should_scroll_up': '_should_scroll_up',
249d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'scroll_loop': '_scroll_loop',
259d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'scroll_interval_ms': '_scroll_interval_ms',
269d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    'scroll_by_pixels': '_scroll_by_pixels',
277868162435adf9082b022a5ba6e00614c7c66381Simon Que    'tasks': '_tasks',
289d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda}
299d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
300ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehoreclass power_LoadTest(test.test):
31145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch    """test class"""
3206548eee3dafcf0fc9ee0dcd15eb607b901ad2c1Benson Leung    version = 2
335cfd7fab4966bf402c4073a41707c31b26cb8c5fAchuith Bhandarkar    _username = 'powerloadtest@gmail.com'
34172ecb7f5a6bbda741799444237a9be4ee21518bEd Baker    _pltp_url = 'https://sites.google.com/a/chromium.org/dev/chromium-os' \
35172ecb7f5a6bbda741799444237a9be4ee21518bEd Baker                '/testing/power-testing/pltp/pltp'
3650fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda
37e7c4cab13a8576a4f9de41b2dc1fb8c45c97424cEric Li
385cfd7fab4966bf402c4073a41707c31b26cb8c5fAchuith Bhandarkar    def initialize(self, percent_initial_charge_min=None,
394f99e9a29b81d14cc94eb711cdb4adb5e66872abSameer Nanda                 check_network=True, loop_time=3600, loop_count=1,
404f99e9a29b81d14cc94eb711cdb4adb5e66872abSameer Nanda                 should_scroll='true', should_scroll_up='true',
414f99e9a29b81d14cc94eb711cdb4adb5e66872abSameer Nanda                 scroll_loop='false', scroll_interval_ms='10000',
4221978453eaa14e284560915268cf9cb1b4604a48Todd Broch                 scroll_by_pixels='600', test_low_batt_p=3,
4359405505bdf7284425645edc162436fd89fb6d51Derek Basehore                 verbose=True, force_wifi=False, wifi_ap='', wifi_sec='none',
4485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni                 wifi_pw='', wifi_timeout=60, tasks='',
453932cc39076c41847e4b8201abb225528b4b815eTodd Broch                 volume_level=10, mic_gain=10, low_batt_margin_p=2,
46f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                 ac_ok=False, log_mem_bandwidth=False, gaia_login=True):
479d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        """
489d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        percent_initial_charge_min: min battery charge at start of test
499d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        check_network: check that Ethernet interface is not running
50417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        loop_time: length of time to run the test for in each loop
51a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        loop_count: number of times to loop the test for
529d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        should_scroll: should the extension scroll pages
539d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        should_scroll_up: should scroll in up direction
549d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        scroll_loop: continue scrolling indefinitely
559d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        scroll_interval_ms: how often to scoll
569d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        scroll_by_pixels: number of pixels to scroll each time
57a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        test_low_batt_p: percent battery at which test should stop
58a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        verbose: add more logging information
59a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        force_wifi: should we force to test to run on wifi
60a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        wifi_ap: the name (ssid) of the wifi access point
61a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        wifi_sec: the type of security for the wifi ap
62a5b3a27862f43e060f9823dd60fa0be18a348862Derek Basehore        wifi_pw: password for the wifi ap
63d7a0f395cd6a36c4f86a88e2bce3b6a6319fbdc8Derek Basehore        wifi_timeout: The timeout for wifi configuration
6405c4b5d1b1417c4e38f184416b0d0ede23cd4e0aTodd Broch        volume_level: percent audio volume level
6505c4b5d1b1417c4e38f184416b0d0ede23cd4e0aTodd Broch        mic_gain: percent audio microphone gain level
66145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch        low_batt_margin_p: percent low battery margin to be added to
67145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch            sys_low_batt_p to guarantee test completes prior to powerd shutdown
683932cc39076c41847e4b8201abb225528b4b815eTodd Broch        ac_ok: boolean to allow running on AC
690d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso        log_mem_bandwidth: boolean to log memory bandwidth during the test
70f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        gaia_login: boolean of whether real GAIA login should be attempted.
719d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        """
72af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        self._backlight = None
736597273abc070f752cd1d57a88556b5f98d96934Derek Basehore        self._services = None
7441acbf89080501db1b554c6919e1e0b3593585ffDerek Basehore        self._browser = None
75417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        self._loop_time = loop_time
76417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        self._loop_count = loop_count
77417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        self._mseconds = self._loop_time * 1000
789d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._verbose = verbose
7921978453eaa14e284560915268cf9cb1b4604a48Todd Broch
8021978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._sys_low_batt_p = 0.
8121978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._sys_low_batt_s = 0.
8221978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._test_low_batt_p = test_low_batt_p
839d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._should_scroll = should_scroll
849d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._should_scroll_up = should_scroll_up
859d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._scroll_loop = scroll_loop
869d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._scroll_interval_ms = scroll_interval_ms
879d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._scroll_by_pixels = scroll_by_pixels
88417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        self._tmp_keyvals = {}
894d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch        self._power_status = None
9059405505bdf7284425645edc162436fd89fb6d51Derek Basehore        self._force_wifi = force_wifi
91b7edff18c59e1caedc32f972551ec68b3620eea5Dale Curtis        self._testServer = None
92fd456804cb8f90f43589f440e0a12c3a7fc7c9d4Derek Basehore        self._tasks = tasks.replace(' ','')
93b312dcf7a07ffdfe5a9625bbb1b5b08e81158b39Jason Glasgow        self._backchannel = None
94f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore        self._shill_proxy = None
9505c4b5d1b1417c4e38f184416b0d0ede23cd4e0aTodd Broch        self._volume_level = volume_level
9605c4b5d1b1417c4e38f184416b0d0ede23cd4e0aTodd Broch        self._mic_gain = mic_gain
973932cc39076c41847e4b8201abb225528b4b815eTodd Broch        self._ac_ok = ac_ok
980d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso        self._log_mem_bandwidth = log_mem_bandwidth
9921978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._wait_time = 60
10021978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._stats = collections.defaultdict(list)
101f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        self._gaia_login = gaia_login
1029d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
1034d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch        if not power_utils.has_battery():
1044d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch            rsp = "Device designed without battery. Skipping test."
1054d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch            raise error.TestNAError(rsp)
1064d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch        self._power_status = power_status.get_status()
1074d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch        self._tmp_keyvals['b_on_ac'] = self._power_status.on_ac()
1084d4f45772fd8e708e019e31fc41f0cfa9d764919Todd Broch
109172ecb7f5a6bbda741799444237a9be4ee21518bEd Baker        with tempfile.NamedTemporaryFile() as pltp:
110172ecb7f5a6bbda741799444237a9be4ee21518bEd Baker            file_utils.download_file(self._pltp_url, pltp.name)
111172ecb7f5a6bbda741799444237a9be4ee21518bEd Baker            self._password = pltp.read().rstrip()
11299c242a22b990e59cac306efa392a2f0f3215bc4Derek Basehore
1133932cc39076c41847e4b8201abb225528b4b815eTodd Broch        if not ac_ok:
1143932cc39076c41847e4b8201abb225528b4b815eTodd Broch            self._power_status.assert_battery_state(percent_initial_charge_min)
11559405505bdf7284425645edc162436fd89fb6d51Derek Basehore        # If force wifi enabled, convert eth0 to backchannel and connect to the
11659405505bdf7284425645edc162436fd89fb6d51Derek Basehore        # specified WiFi AP.
11759405505bdf7284425645edc162436fd89fb6d51Derek Basehore        if self._force_wifi:
118ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            sec_config = None
119ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            # TODO(dbasehore): Fix this when we get a better way of figuring out
120ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            # the wifi security configuration.
121ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            if wifi_sec == 'rsn' or wifi_sec == 'wpa':
122ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                sec_config = xmlrpc_security_types.WPAConfig(
123ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        psk=wifi_pw,
124ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wpa_mode=xmlrpc_security_types.WPAConfig.MODE_PURE_WPA2,
125ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wpa2_ciphers=
126ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                                [xmlrpc_security_types.WPAConfig.CIPHER_CCMP])
127ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            wifi_config = xmlrpc_datatypes.AssociationParameters(
128d7a0f395cd6a36c4f86a88e2bce3b6a6319fbdc8Derek Basehore                    ssid=wifi_ap, security_config=sec_config,
129d7a0f395cd6a36c4f86a88e2bce3b6a6319fbdc8Derek Basehore                    configuration_timeout=wifi_timeout)
1309450ad9bc6e5537d93f31bd53f161067fb13a1d5Dale Curtis            # If backchannel is already running, don't run it again.
131b312dcf7a07ffdfe5a9625bbb1b5b08e81158b39Jason Glasgow            self._backchannel = backchannel.Backchannel()
132b312dcf7a07ffdfe5a9625bbb1b5b08e81158b39Jason Glasgow            if not self._backchannel.setup():
1339450ad9bc6e5537d93f31bd53f161067fb13a1d5Dale Curtis                raise error.TestError('Could not setup Backchannel network.')
1349450ad9bc6e5537d93f31bd53f161067fb13a1d5Dale Curtis
135f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore            self._shill_proxy = wifi_proxy.WifiProxy()
136f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore            self._shill_proxy.remove_all_wifi_entries()
137d996e409a3debba138a3ed9523d6a2cad49b210aTodd Broch            for i in xrange(1,4):
138f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore                raw_output = self._shill_proxy.connect_to_wifi_network(
139ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wifi_config.ssid,
140ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wifi_config.security,
141ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wifi_config.security_parameters,
142ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        wifi_config.save_credentials,
143ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        station_type=wifi_config.station_type,
144ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        hidden_network=wifi_config.is_hidden,
145ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        discovery_timeout_seconds=
146ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                                wifi_config.discovery_timeout,
147ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        association_timeout_seconds=
148ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                                wifi_config.association_timeout,
149ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        configuration_timeout_seconds=
150d996e409a3debba138a3ed9523d6a2cad49b210aTodd Broch                                wifi_config.configuration_timeout * i)
151ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                result = xmlrpc_datatypes.AssociationResult. \
152ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                        from_dbus_proxy_output(raw_output)
153ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                if result.success:
154ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore                    break
155d996e409a3debba138a3ed9523d6a2cad49b210aTodd Broch                logging.warn('wifi connect: disc:%d assoc:%d config:%d fail:%s',
156d996e409a3debba138a3ed9523d6a2cad49b210aTodd Broch                             result.discovery_time, result.association_time,
157d996e409a3debba138a3ed9523d6a2cad49b210aTodd Broch                             result.configuration_time, result.failure_reason)
158ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore            else:
1599450ad9bc6e5537d93f31bd53f161067fb13a1d5Dale Curtis                raise error.TestError('Could not connect to WiFi network.')
160ccc390b2d0087b860cecd8086ea25a2326ffa144Derek Basehore
161278b5370c7d022768e0ab319ce7f439a877e4443Simon Que        else:
162278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            # Find all wired ethernet interfaces.
163278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            # TODO: combine this with code in network_DisableInterface, in a
164278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            # common library somewhere.
165278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            ifaces = [ nic.strip() for nic in os.listdir('/sys/class/net/')
166278b5370c7d022768e0ab319ce7f439a877e4443Simon Que                if ((not os.path.exists('/sys/class/net/' + nic + '/phy80211'))
167278b5370c7d022768e0ab319ce7f439a877e4443Simon Que                    and nic.find('eth') != -1) ]
168278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            logging.debug(str(ifaces))
169278b5370c7d022768e0ab319ce7f439a877e4443Simon Que            for iface in ifaces:
1701bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant                if check_network and self._is_network_iface_running(iface):
171ee79b397f23b6fd21a668b24264ce4c331d4d129Todd Broch                    raise error.TestError('Ethernet interface is active. ' +
172ee79b397f23b6fd21a668b24264ce4c331d4d129Todd Broch                                          'Please remove Ethernet cable')
1739d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
174d075074b8fc70d829912864f819345407295f35dSameer Nanda        # record the max backlight level
175af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        self._backlight = power_utils.Backlight()
176af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        self._tmp_keyvals['level_backlight_max'] = \
177af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch            self._backlight.get_max_level()
1786a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
179d16f1daab3a354b637065b99dbc31809ce5674ddAlex Miller        self._services = service_stopper.ServiceStopper(
180d16f1daab3a354b637065b99dbc31809ce5674ddAlex Miller            service_stopper.ServiceStopper.POWER_DRAW_SERVICES)
181d16f1daab3a354b637065b99dbc31809ce5674ddAlex Miller        self._services.stop_services()
182d16f1daab3a354b637065b99dbc31809ce5674ddAlex Miller
1839d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        # fix up file perms for the power test extension so that chrome
1849d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        # can access it
185ce1407b29b32f8f8fb1121251e28f0861ecac6a8Sameer Nanda        os.system('chmod -R 755 %s' % self.bindir)
1869d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
1876a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        # setup a HTTP Server to listen for status updates from the power
1886a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        # test extension
189c4d8f4aab4e434fcb1a9fb33931768ffebfb8f1cEric Li        self._testServer = httpd.HTTPListener(8001, docroot=self.bindir)
1906a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        self._testServer.run()
1916a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
19287aced24632053d9df0a42842307abf165f60ad1Sameer Nanda        # initialize various interesting power related stats
19369324998af43b8992df694370a8536bad2da2f9cTodd Broch        self._statomatic = power_status.StatoMatic()
194417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
1954ae320f5b4afd9c047dfa446d76722100c03665bJulius Werner        self._power_status.refresh()
19606ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        help_output = utils.system_output('check_powerd_config --help')
19706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        if 'low_battery_shutdown' in help_output:
19806ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          logging.info('Have low_battery_shutdown option')
19906ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          self._sys_low_batt_p = float(utils.system_output(
20006ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan                  'check_powerd_config --low_battery_shutdown_percent'))
20106ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          self._sys_low_batt_s = int(utils.system_output(
20206ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan                  'check_powerd_config --low_battery_shutdown_time'))
20306ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        else:
20406ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          # TODO(dchan) Once M57 in stable, remove this option and function.
20506ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          logging.info('No low_battery_shutdown option')
20606ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          (self._sys_low_batt_p, self._sys_low_batt_s) = \
20706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan              self._get_sys_low_batt_values_from_log()
2088b4fdc2687016da15a37da7767bc97d97186f647Daniel Erat
2098b4fdc2687016da15a37da7767bc97d97186f647Daniel Erat        if self._sys_low_batt_p and self._sys_low_batt_s:
2108b4fdc2687016da15a37da7767bc97d97186f647Daniel Erat            raise error.TestError(
2118b4fdc2687016da15a37da7767bc97d97186f647Daniel Erat                    "Low battery percent and seconds are non-zero.")
2128b4fdc2687016da15a37da7767bc97d97186f647Daniel Erat
213145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch        min_low_batt_p = min(self._sys_low_batt_p + low_batt_margin_p, 100)
214145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch        if self._sys_low_batt_p and (min_low_batt_p > self._test_low_batt_p):
21504be2bd5e4666a5c253e9c30ab20555e04286032Ilja H. Friedel            logging.warning("test low battery threshold is below system " +
21621978453eaa14e284560915268cf9cb1b4604a48Todd Broch                         "low battery requirement.  Setting to %f",
217145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch                         min_low_batt_p)
218145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch            self._test_low_batt_p = min_low_batt_p
2194ae320f5b4afd9c047dfa446d76722100c03665bJulius Werner
2209d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._ah_charge_start = self._power_status.battery[0].charge_now
2219d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        self._wh_energy_start = self._power_status.battery[0].energy
2229d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
22306ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
22406548eee3dafcf0fc9ee0dcd15eb607b901ad2c1Benson Leung    def run_once(self):
225417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        t0 = time.time()
226417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
22767cdc80fd1d8fcc604332ad9f3d03feff3bab5d8Todd Broch        # record the PSR related info.
22867cdc80fd1d8fcc604332ad9f3d03feff3bab5d8Todd Broch        psr = power_utils.DisplayPanelSelfRefresh(init_time=t0)
229edfd5ba0e55670be04143d919b7d559b56a9bf35Eric Caruso
2302f156e8967fab4b4ffe38cd727aaeabf5e4080f6Todd Broch        try:
23185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            self._keyboard_backlight = power_utils.KbdBacklight()
23285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            self._set_keyboard_backlight_level()
2332f156e8967fab4b4ffe38cd727aaeabf5e4080f6Todd Broch        except power_utils.KbdBacklightException as e:
2342f156e8967fab4b4ffe38cd727aaeabf5e4080f6Todd Broch            logging.info("Assuming no keyboard backlight due to :: %s", str(e))
23585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            self._keyboard_backlight = None
2362f156e8967fab4b4ffe38cd727aaeabf5e4080f6Todd Broch
2372ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        measurements = \
2382ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch            [power_status.SystemPower(self._power_status.battery_path)]
2392ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        if power_utils.has_rapl_support():
2402ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch            measurements += power_rapl.create_rapl()
2412ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        self._plog = power_status.PowerLogger(measurements, seconds_period=20)
242be3c3e70c41e5e28a88dad5b7062dd9baf6af091Todd Broch        self._tlog = power_status.TempLogger([], seconds_period=20)
2432ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        self._plog.start()
244be3c3e70c41e5e28a88dad5b7062dd9baf6af091Todd Broch        self._tlog.start()
2450d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso        if self._log_mem_bandwidth:
2460d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso            self._mlog = memory_bandwidth_logger.MemoryBandwidthLogger(
2470d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso                raw=False, seconds_period=2)
2480d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso            self._mlog.start()
2492ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch
2500ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehore        ext_path = os.path.join(os.path.dirname(__file__), 'extension')
251f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        self._tmp_keyvals['username'] = self._username
252f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        try:
253f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            self._browser = chrome.Chrome(extension_paths=[ext_path],
254f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                                          gaia_login=self._gaia_login,
255f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                                          username=self._username,
256f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                                          password=self._password)
257f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        except exceptions.LoginException:
258f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            # already failed guest login
259f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            if not self._gaia_login:
260f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                raise
261f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            self._gaia_login = False
262f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            logging.warn("Unable to use GAIA acct %s.  Using GUEST instead.\n",
263f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                         self._username)
264f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            self._browser = chrome.Chrome(extension_paths=[ext_path],
265f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                                          gaia_login=self._gaia_login)
266f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        if not self._gaia_login:
267f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            self._tmp_keyvals['username'] = 'GUEST'
268f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch
26941acbf89080501db1b554c6919e1e0b3593585ffDerek Basehore        extension = self._browser.get_extension(ext_path)
270fd456804cb8f90f43589f440e0a12c3a7fc7c9d4Derek Basehore        for k in params_dict:
271fd456804cb8f90f43589f440e0a12c3a7fc7c9d4Derek Basehore            if getattr(self, params_dict[k]) is not '':
272fd456804cb8f90f43589f440e0a12c3a7fc7c9d4Derek Basehore                extension.ExecuteJavaScript('var %s = %s;' %
273fd456804cb8f90f43589f440e0a12c3a7fc7c9d4Derek Basehore                                            (k, getattr(self, params_dict[k])))
2740ecaa5c74b6943368ba80cedca2259931f51426aDerek Basehore
275deac9bc81f75261120c42458da2c26e08987117fDerek Basehore        # This opens a trap start page to capture tabs opened for first login.
276deac9bc81f75261120c42458da2c26e08987117fDerek Basehore        # It will be closed when startTest is run.
277deac9bc81f75261120c42458da2c26e08987117fDerek Basehore        extension.ExecuteJavaScript('chrome.windows.create(null, null);')
278deac9bc81f75261120c42458da2c26e08987117fDerek Basehore
279417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        for i in range(self._loop_count):
2802ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch            start_time = time.time()
281664bad8943c04684b1181e53dc0e58d598733c55Derek Basehore            extension.ExecuteJavaScript('startTest();')
282fd4caad0dadc545b7458c16c2340fecfbfd1fe40Todd Broch            # the power test extension will report its status here
283fd4caad0dadc545b7458c16c2340fecfbfd1fe40Todd Broch            latch = self._testServer.add_wait_url('/status')
284d075074b8fc70d829912864f819345407295f35dSameer Nanda
2857c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # this starts a thread in the server that listens to log
2867c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # information from the script
2877c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            script_logging = self._testServer.add_wait_url(url='/log')
2887c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon
2897c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # dump any log entry that comes from the script into
2907c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # the debug log
2917c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            self._testServer.add_url_handler(url='/log',\
2927c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon                handler_func=(lambda handler, forms, loop_counter=i:\
2937c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon                    _extension_log_handler(handler, forms, loop_counter)))
2947c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon
295ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            pagelt_tracking = self._testServer.add_wait_url(url='/pagelt')
296ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
297ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            self._testServer.add_url_handler(url='/pagelt',\
298ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon                handler_func=(lambda handler, forms, tracker=self, loop_counter=i:\
299ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon                    _extension_page_load_info_handler(handler, forms, loop_counter, self)))
300ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
301d075074b8fc70d829912864f819345407295f35dSameer Nanda            # reset backlight level since powerd might've modified it
302d075074b8fc70d829912864f819345407295f35dSameer Nanda            # based on ambient light
303d075074b8fc70d829912864f819345407295f35dSameer Nanda            self._set_backlight_level()
304698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch            self._set_lightbar_level()
30585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            if self._keyboard_backlight:
30685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni                self._set_keyboard_backlight_level()
30730561af7cc67403c50ba09f5a14258e1c34e3006Hsin-Yu Chao            audio_helper.set_volume_levels(self._volume_level,
30830561af7cc67403c50ba09f5a14258e1c34e3006Hsin-Yu Chao                                           self._mic_gain)
309d075074b8fc70d829912864f819345407295f35dSameer Nanda
310417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            low_battery = self._do_wait(self._verbose, self._loop_time,
31106548eee3dafcf0fc9ee0dcd15eb607b901ad2c1Benson Leung                                        latch)
312417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
3137c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            script_logging.set();
314ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            pagelt_tracking.set();
3152ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch            self._plog.checkpoint('loop%d' % (i), start_time)
316be3c3e70c41e5e28a88dad5b7062dd9baf6af091Todd Broch            self._tlog.checkpoint('loop%d' % (i), start_time)
317417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            if self._verbose:
318145cb75b5c33f590ddcb9421e8b3c3fbeae7117fTodd Broch                logging.debug('loop %d completed', i)
319417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
320417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            if low_battery:
321417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                logging.info('Exiting due to low battery')
322417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                break
3236a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
3247c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon        # done with logging from the script, so we can collect that thread
325417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        t1 = time.time()
32667cdc80fd1d8fcc604332ad9f3d03feff3bab5d8Todd Broch        psr.refresh()
32721978453eaa14e284560915268cf9cb1b4604a48Todd Broch        self._tmp_keyvals['minutes_battery_life_tested'] = (t1 - t0) / 60
32867cdc80fd1d8fcc604332ad9f3d03feff3bab5d8Todd Broch        self._tmp_keyvals.update(psr.get_keyvals())
3296a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
3306a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda
3316a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda    def postprocess_iteration(self):
33221978453eaa14e284560915268cf9cb1b4604a48Todd Broch        def _log_stats(prefix, stats):
33321978453eaa14e284560915268cf9cb1b4604a48Todd Broch            if not len(stats):
33421978453eaa14e284560915268cf9cb1b4604a48Todd Broch                return
33521978453eaa14e284560915268cf9cb1b4604a48Todd Broch            np = numpy.array(stats)
33621978453eaa14e284560915268cf9cb1b4604a48Todd Broch            logging.debug("%s samples: %d", prefix, len(np))
33721978453eaa14e284560915268cf9cb1b4604a48Todd Broch            logging.debug("%s mean:    %.2f", prefix, np.mean())
33821978453eaa14e284560915268cf9cb1b4604a48Todd Broch            logging.debug("%s stdev:   %.2f", prefix, np.std())
33921978453eaa14e284560915268cf9cb1b4604a48Todd Broch            logging.debug("%s max:     %.2f", prefix, np.max())
34021978453eaa14e284560915268cf9cb1b4604a48Todd Broch            logging.debug("%s min:     %.2f", prefix, np.min())
34121978453eaa14e284560915268cf9cb1b4604a48Todd Broch
34221978453eaa14e284560915268cf9cb1b4604a48Todd Broch
34321978453eaa14e284560915268cf9cb1b4604a48Todd Broch        def _log_per_loop_stats():
34421978453eaa14e284560915268cf9cb1b4604a48Todd Broch            samples_per_loop = self._loop_time / self._wait_time + 1
34521978453eaa14e284560915268cf9cb1b4604a48Todd Broch            for kname in self._stats:
34621978453eaa14e284560915268cf9cb1b4604a48Todd Broch                start_idx = 0
34721978453eaa14e284560915268cf9cb1b4604a48Todd Broch                loop = 1
34821978453eaa14e284560915268cf9cb1b4604a48Todd Broch                for end_idx in xrange(samples_per_loop, len(self._stats[kname]),
34921978453eaa14e284560915268cf9cb1b4604a48Todd Broch                                      samples_per_loop):
35021978453eaa14e284560915268cf9cb1b4604a48Todd Broch                    _log_stats("%s loop %d" % (kname, loop),
35121978453eaa14e284560915268cf9cb1b4604a48Todd Broch                               self._stats[kname][start_idx:end_idx])
35221978453eaa14e284560915268cf9cb1b4604a48Todd Broch                    loop += 1
35321978453eaa14e284560915268cf9cb1b4604a48Todd Broch                    start_idx = end_idx
35421978453eaa14e284560915268cf9cb1b4604a48Todd Broch
35521978453eaa14e284560915268cf9cb1b4604a48Todd Broch
35621978453eaa14e284560915268cf9cb1b4604a48Todd Broch        def _log_all_stats():
35721978453eaa14e284560915268cf9cb1b4604a48Todd Broch            for kname in self._stats:
35821978453eaa14e284560915268cf9cb1b4604a48Todd Broch                _log_stats(kname, self._stats[kname])
35921978453eaa14e284560915268cf9cb1b4604a48Todd Broch
36021978453eaa14e284560915268cf9cb1b4604a48Todd Broch
3612ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        keyvals = self._plog.calc()
362be3c3e70c41e5e28a88dad5b7062dd9baf6af091Todd Broch        keyvals.update(self._tlog.calc())
36369324998af43b8992df694370a8536bad2da2f9cTodd Broch        keyvals.update(self._statomatic.publish())
36421978453eaa14e284560915268cf9cb1b4604a48Todd Broch
3650d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso        if self._log_mem_bandwidth:
3660d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso            self._mlog.stop()
3670d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso            self._mlog.join()
3680d61ffb567a6d0e55c332b0ab1e05caf01000b77Eric Caruso
36921978453eaa14e284560915268cf9cb1b4604a48Todd Broch        _log_all_stats()
37021978453eaa14e284560915268cf9cb1b4604a48Todd Broch        _log_per_loop_stats()
371c4133d233aa092c4cb9d6e399baaad4eaa16d187Julius Werner
37287aced24632053d9df0a42842307abf165f60ad1Sameer Nanda        # record battery stats
37350fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda        keyvals['a_current_now'] = self._power_status.battery[0].current_now
3749d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['ah_charge_full'] = self._power_status.battery[0].charge_full
3756a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        keyvals['ah_charge_full_design'] = \
3769d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda                             self._power_status.battery[0].charge_full_design
3779d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['ah_charge_start'] = self._ah_charge_start
3789d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['ah_charge_now'] = self._power_status.battery[0].charge_now
37950fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda        keyvals['ah_charge_used'] = keyvals['ah_charge_start'] - \
38050fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda                                    keyvals['ah_charge_now']
3819d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['wh_energy_start'] = self._wh_energy_start
3829d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['wh_energy_now'] = self._power_status.battery[0].energy
38350fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda        keyvals['wh_energy_used'] = keyvals['wh_energy_start'] - \
38450fb54165e35caebc1bd90d409fcba0fe0b01658Sameer Nanda                                    keyvals['wh_energy_now']
3856a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        keyvals['v_voltage_min_design'] = \
3869d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda                             self._power_status.battery[0].voltage_min_design
38721978453eaa14e284560915268cf9cb1b4604a48Todd Broch        keyvals['wh_energy_full_design'] = \
38821978453eaa14e284560915268cf9cb1b4604a48Todd Broch                             self._power_status.battery[0].energy_full_design
3899d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        keyvals['v_voltage_now'] = self._power_status.battery[0].voltage_now
3909d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
391417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        keyvals.update(self._tmp_keyvals)
392417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
39321978453eaa14e284560915268cf9cb1b4604a48Todd Broch        keyvals['percent_sys_low_battery'] = self._sys_low_batt_p
39421978453eaa14e284560915268cf9cb1b4604a48Todd Broch        keyvals['seconds_sys_low_battery'] = self._sys_low_batt_s
39521978453eaa14e284560915268cf9cb1b4604a48Todd Broch        voltage_np = numpy.array(self._stats['v_voltage_now'])
39621978453eaa14e284560915268cf9cb1b4604a48Todd Broch        voltage_mean = voltage_np.mean()
39721978453eaa14e284560915268cf9cb1b4604a48Todd Broch        keyvals['v_voltage_mean'] = voltage_mean
3983932cc39076c41847e4b8201abb225528b4b815eTodd Broch
3992633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        keyvals['wh_energy_powerlogger'] = \
4002633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso                             self._energy_use_from_powerlogger(keyvals)
4012633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
402c9c0fe619af775caca6a67928c77a00c84eb1a22Todd Broch        if keyvals['ah_charge_used'] > 0 and not self._power_status.on_ac():
40361b032031e418fece0430cf13bd84fff239ac603Eric Caruso            # For full runs, we should use charge to scale for battery life,
40461b032031e418fece0430cf13bd84fff239ac603Eric Caruso            # since the voltage swing is accounted for.
40561b032031e418fece0430cf13bd84fff239ac603Eric Caruso            # For short runs, energy will be a better estimate.
40661b032031e418fece0430cf13bd84fff239ac603Eric Caruso            if self._loop_count > 1:
40761b032031e418fece0430cf13bd84fff239ac603Eric Caruso                estimated_reps = (keyvals['ah_charge_full_design'] /
40861b032031e418fece0430cf13bd84fff239ac603Eric Caruso                                  keyvals['ah_charge_used'])
40961b032031e418fece0430cf13bd84fff239ac603Eric Caruso            else:
41061b032031e418fece0430cf13bd84fff239ac603Eric Caruso                estimated_reps = (keyvals['wh_energy_full_design'] /
41161b032031e418fece0430cf13bd84fff239ac603Eric Caruso                                  keyvals['wh_energy_powerlogger'])
41261b032031e418fece0430cf13bd84fff239ac603Eric Caruso
41361b032031e418fece0430cf13bd84fff239ac603Eric Caruso            bat_life_scale =  estimated_reps * \
4143932cc39076c41847e4b8201abb225528b4b815eTodd Broch                              ((100 - keyvals['percent_sys_low_battery']) / 100)
4153932cc39076c41847e4b8201abb225528b4b815eTodd Broch
4163932cc39076c41847e4b8201abb225528b4b815eTodd Broch            keyvals['minutes_battery_life'] = bat_life_scale * \
4173932cc39076c41847e4b8201abb225528b4b815eTodd Broch                keyvals['minutes_battery_life_tested']
4183932cc39076c41847e4b8201abb225528b4b815eTodd Broch            # In the case where sys_low_batt_s is non-zero subtract those
4193932cc39076c41847e4b8201abb225528b4b815eTodd Broch            # minutes from the final extrapolation.
4203932cc39076c41847e4b8201abb225528b4b815eTodd Broch            if self._sys_low_batt_s:
4213932cc39076c41847e4b8201abb225528b4b815eTodd Broch                keyvals['minutes_battery_life'] -= self._sys_low_batt_s / 60
4223932cc39076c41847e4b8201abb225528b4b815eTodd Broch
4233932cc39076c41847e4b8201abb225528b4b815eTodd Broch            keyvals['a_current_rate'] = keyvals['ah_charge_used'] * 60 / \
4243932cc39076c41847e4b8201abb225528b4b815eTodd Broch                                        keyvals['minutes_battery_life_tested']
4253932cc39076c41847e4b8201abb225528b4b815eTodd Broch            keyvals['w_energy_rate'] = keyvals['wh_energy_used'] * 60 / \
4263932cc39076c41847e4b8201abb225528b4b815eTodd Broch                                       keyvals['minutes_battery_life_tested']
427f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            if self._gaia_login:
428f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                self.output_perf_value(description='minutes_battery_life',
429f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                                       value=keyvals['minutes_battery_life'],
430a6dd50ff53321257030bf96069f20f107c3dece6Derek Basehore                                       units='minutes',
431a6dd50ff53321257030bf96069f20f107c3dece6Derek Basehore                                       higher_is_better=True)
432e2ad5763d4db741f6ffdcb89479a97c6fbd628f5Todd Broch
433f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch        if not self._gaia_login:
434f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch            keyvals = dict(map(lambda (key, value):
435f77f59bfb5bcb0c3ea6582502a493db8bd1de4f9Todd Broch                               ('INVALID_' + str(key), value), keyvals.items()))
436e2ad5763d4db741f6ffdcb89479a97c6fbd628f5Todd Broch        else:
4376083c7b520ddfdbb524baf626d5715013be8dbebRavi Chandra Sadineni            for key, value in keyvals.iteritems():
4386083c7b520ddfdbb524baf626d5715013be8dbebRavi Chandra Sadineni                if key.startswith('percent_cpuidle') and \
4396083c7b520ddfdbb524baf626d5715013be8dbebRavi Chandra Sadineni                   key.endswith('C0_time'):
4406083c7b520ddfdbb524baf626d5715013be8dbebRavi Chandra Sadineni                    self.output_perf_value(description=key,
441a6dd50ff53321257030bf96069f20f107c3dece6Derek Basehore                                           value=value,
442a6dd50ff53321257030bf96069f20f107c3dece6Derek Basehore                                           units='percent',
443a6dd50ff53321257030bf96069f20f107c3dece6Derek Basehore                                           higher_is_better=False)
444e2ad5763d4db741f6ffdcb89479a97c6fbd628f5Todd Broch
4456a0746595cb21c52db2b4ef2e03ff1d73a75c1d0Sameer Nanda        self.write_perf_keyval(keyvals)
4462ea62250aa5ee9d9960c9f65a9501da6fd53ca8aTodd Broch        self._plog.save_results(self.resultsdir)
447be3c3e70c41e5e28a88dad5b7062dd9baf6af091Todd Broch        self._tlog.save_results(self.resultsdir)
4489d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4499d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4509d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda    def cleanup(self):
451af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        if self._backlight:
452af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch            self._backlight.restore()
453187240b15fe210be911c5dfc2a414d0780d9be7dTodd Broch        if self._services:
454187240b15fe210be911c5dfc2a414d0780d9be7dTodd Broch            self._services.restore_services()
455187240b15fe210be911c5dfc2a414d0780d9be7dTodd Broch
456b5056ea955d1997ce7d28441656f6134b30a1a07Dale Curtis        # cleanup backchannel interface
457f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore        # Prevent wifi congestion in test lab by forcing machines to forget the
458f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore        # wifi AP we connected to at the start of the test.
459f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore        if self._shill_proxy:
460f10a3198906c17a539c830e1263e6efb0a3db7b2Derek Basehore            self._shill_proxy.remove_all_wifi_entries()
461b312dcf7a07ffdfe5a9625bbb1b5b08e81158b39Jason Glasgow        if self._backchannel:
462b312dcf7a07ffdfe5a9625bbb1b5b08e81158b39Jason Glasgow            self._backchannel.teardown()
46341acbf89080501db1b554c6919e1e0b3593585ffDerek Basehore        if self._browser:
46441acbf89080501db1b554c6919e1e0b3593585ffDerek Basehore            self._browser.close()
465b7edff18c59e1caedc32f972551ec68b3620eea5Dale Curtis        if self._testServer:
466b7edff18c59e1caedc32f972551ec68b3620eea5Dale Curtis            self._testServer.stop()
4679d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4689d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4692e56d3461849c3066023f0f6e9e9060523d72d30Mike Truty    def _do_wait(self, verbose, seconds, latch):
4709d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda        latched = False
471417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        low_battery = False
47221978453eaa14e284560915268cf9cb1b4604a48Todd Broch        total_time = seconds + self._wait_time
4732e56d3461849c3066023f0f6e9e9060523d72d30Mike Truty        elapsed_time = 0
4749d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4752e56d3461849c3066023f0f6e9e9060523d72d30Mike Truty        while elapsed_time < total_time:
47621978453eaa14e284560915268cf9cb1b4604a48Todd Broch            time.sleep(self._wait_time)
47721978453eaa14e284560915268cf9cb1b4604a48Todd Broch            elapsed_time += self._wait_time
4789d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
4799d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda            self._power_status.refresh()
480c9c0fe619af775caca6a67928c77a00c84eb1a22Todd Broch
481c9c0fe619af775caca6a67928c77a00c84eb1a22Todd Broch            if not self._ac_ok and self._power_status.on_ac():
482c9c0fe619af775caca6a67928c77a00c84eb1a22Todd Broch                raise error.TestError('Running on AC power now.')
483c9c0fe619af775caca6a67928c77a00c84eb1a22Todd Broch
48421978453eaa14e284560915268cf9cb1b4604a48Todd Broch            charge_now = self._power_status.battery[0].charge_now
48521978453eaa14e284560915268cf9cb1b4604a48Todd Broch            energy_rate = self._power_status.battery[0].energy_rate
48621978453eaa14e284560915268cf9cb1b4604a48Todd Broch            voltage_now = self._power_status.battery[0].voltage_now
48721978453eaa14e284560915268cf9cb1b4604a48Todd Broch            self._stats['w_energy_rate'].append(energy_rate)
48821978453eaa14e284560915268cf9cb1b4604a48Todd Broch            self._stats['v_voltage_now'].append(voltage_now)
489417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            if verbose:
49021978453eaa14e284560915268cf9cb1b4604a48Todd Broch                logging.debug('ah_charge_now %f', charge_now)
49121978453eaa14e284560915268cf9cb1b4604a48Todd Broch                logging.debug('w_energy_rate %f', energy_rate)
49221978453eaa14e284560915268cf9cb1b4604a48Todd Broch                logging.debug('v_voltage_now %f', voltage_now)
493417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
494cfa1ddf94edc7ac518a178415ec4a7c9a61a9dd6Todd Broch            low_battery = (self._power_status.percent_current_charge() <
49521978453eaa14e284560915268cf9cb1b4604a48Todd Broch                           self._test_low_batt_p)
496417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
497417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            latched = latch.is_set()
498417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda
499417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            if latched or low_battery:
5009d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda                break
5019d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
502417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        if latched:
503417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            # record chrome power extension stats
504417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            form_data = self._testServer.get_form_entries()
505417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            logging.debug(form_data)
506417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda            for e in form_data:
507417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                key = 'ext_' + e
508417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                if key in self._tmp_keyvals:
509a8d49fffc08e05a5cccaa5821c84bd4ca86768a8Todd Broch                    self._tmp_keyvals[key] += "_%s" % form_data[e]
510417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                else:
511417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda                    self._tmp_keyvals[key] = form_data[e]
512417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        else:
5139d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda            logging.debug("Didn't get status back from power extension")
5149d4bcb6d907ad23d947f65d3c764c8ee3848e7d3Sameer Nanda
515417da5be901b3e68131017e1a631bdd84835b1d2Sameer Nanda        return low_battery
516d075074b8fc70d829912864f819345407295f35dSameer Nanda
51706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
518d075074b8fc70d829912864f819345407295f35dSameer Nanda    def _set_backlight_level(self):
519af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        self._backlight.set_default()
520d075074b8fc70d829912864f819345407295f35dSameer Nanda        # record brightness level
521af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch        self._tmp_keyvals['level_backlight_current'] = \
522af5de98643110a67a9f5c323dd56be3eb1e35448Todd Broch            self._backlight.get_level()
523698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch
524698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch
525698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch    def _set_lightbar_level(self, level='off'):
526698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        """Set lightbar level.
527698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch
528698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        Args:
529698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch          level: string value to set lightbar to.  See ectool for more details.
530698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        """
531698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        rv = utils.system('which ectool', ignore_status=True)
532698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        if rv:
533698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch            return
534698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        rv = utils.system('ectool lightbar %s' % level, ignore_status=True)
535698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        if rv:
536698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch            logging.info('Assuming no lightbar due to non-zero exit status')
537698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch        else:
538698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch            logging.info('Setting lightbar to %s', level)
539698956153242dfb51ebdaadef4317749c7fc4be0Todd Broch            self._tmp_keyvals['level_lightbar_current'] = level
54021978453eaa14e284560915268cf9cb1b4604a48Todd Broch
54121978453eaa14e284560915268cf9cb1b4604a48Todd Broch
54206ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan    def _get_sys_low_batt_values_from_log(self):
54306ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        """Determine the low battery values for device and return.
54406ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
54506ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        2012/11/01: power manager (powerd.cc) parses parameters in filesystem
54606ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          and outputs a log message like:
54706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
54806ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan           [1101/173837:INFO:powerd.cc(258)] Using low battery time threshold
54906ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan                     of 0 secs and using low battery percent threshold of 3.5
55006ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
55106ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan           It currently checks to make sure that only one of these values is
55206ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan           defined.
55306ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
55406ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        Returns:
55506ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan          Tuple of (percent, seconds)
55606ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan            percent: float of low battery percentage
55706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan            seconds: float of low battery seconds
55806ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
55906ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        """
56006ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        split_re = 'threshold of'
56106ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
56206ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        powerd_log = '/var/log/power_manager/powerd.LATEST'
56306ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        cmd = 'grep "low battery time" %s' % powerd_log
56406ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        line = utils.system_output(cmd)
56506ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        secs = float(line.split(split_re)[1].split()[0])
56606ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        percent = float(line.split(split_re)[2].split()[0])
56706ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan        return (percent, secs)
56806ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
56906ed53a4b7da6f629cb6a4076ed27ff5f07ddccbDanny Chan
57085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni    def _has_light_sensor(self):
57185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
57285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Determine if there is a light sensor on the board.
57385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
57485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        @returns True if this host has a light sensor or
57585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni                 False if it does not.
57685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
57785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        # If the command exits with a failure status,
57885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        # we do not have a light sensor
57985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        cmd = 'check_powerd_config --ambient_light_sensor'
5805ed7e63aeec90dc0c6b4229a66bf161410aa86a6Allen Li        result = utils.run(cmd, ignore_status=True)
58185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        if result.exit_status:
58285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            logging.debug('Ambient light sensor not present')
58385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            return False
58485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        logging.debug('Ambient light sensor present')
58585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        return True
58685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
58785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
5881bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant    def _is_network_iface_running(self, name):
5891bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        """
5901bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        Checks to see if the interface is running.
5911bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant
5921bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        Args:
5931bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant          name: name of the interface to check.
5941bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant
5951bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        Returns:
5961bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant          True if the interface is running.
5971bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant
5981bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        """
5991bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        try:
6001bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant            # TODO: Switch to 'ip' (crbug.com/410601).
6011bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant            out = utils.system_output('ifconfig %s' % name)
6021bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        except error.CmdError, e:
6031bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant            logging.info(e)
6041bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant            return False
6051bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant
6061bc91d6b5e86fe30b2c1b6bb74262c57c1ec7e35Christopher Grant        return out.find('RUNNING') >= 0
6072633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
6082633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
6092633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso    def _energy_use_from_powerlogger(self, keyval):
6102633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        """
6112633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        Calculates the energy use, in Wh, used over the course of the run as
6122633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        reported by the PowerLogger.
6132633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
6142633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        Args:
6152633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso          keyval: the dictionary of keyvals containing PowerLogger output
6162633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
6172633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        Returns:
6182633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso          energy_wh: total energy used over the course of this run
6192633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso
6202633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        """
6212633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        energy_wh = 0
6222633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        loop = 0
6232633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        while True:
6242633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso            duration_key = 'loop%d_system_duration' % loop
6252633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso            avg_power_key = 'loop%d_system_pwr' % loop
6262633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso            if duration_key not in keyval or avg_power_key not in keyval:
6272633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso                break
6282633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso            energy_wh += keyval[duration_key] * keyval[avg_power_key] / 3600
6292633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso            loop += 1
6302633eef2994f6d798f2c22000c006063bee1ae85Eric Caruso        return energy_wh
63185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
63285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
63385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni    def _has_hover_detection(self):
63485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
63585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Checks if hover is detected by the device.
63685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
63785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Returns:
63885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            Returns True if the hover detection support is enabled.
63985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            Else returns false.
64085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
64185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
64285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        cmd = 'check_powerd_config --hover_detection'
6435ed7e63aeec90dc0c6b4229a66bf161410aa86a6Allen Li        result = utils.run(cmd, ignore_status=True)
64485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        if result.exit_status:
64585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            logging.debug('Hover not present')
64685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            return False
64785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        logging.debug('Hover present')
64885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        return True
64985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
65085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
65185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni    def _set_keyboard_backlight_level(self):
65285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
65385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Sets keyboard backlight based on light sensor and hover.
65485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        These values are based on UMA as mentioned in
65585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        https://bugs.chromium.org/p/chromium/issues/detail?id=603233#c10
65685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
65785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        ALS  | hover | keyboard backlight level
65885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        ---------------------------------------
65985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        No   | No    | default
66085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        ---------------------------------------
66185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Yes  | No    | 40% of default
66285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        --------------------------------------
66385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        No   | Yes   | System with this configuration does not exist
66485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        --------------------------------------
66585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Yes  | Yes   | 30% of default
66685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        --------------------------------------
66785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
66885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        Here default is no Ambient Light Sensor, no hover,
66985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        default always-on brightness level.
67085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        """
67185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
67285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        default_level = self._keyboard_backlight.get_default_level()
67385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        level_to_set = default_level
67485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        has_light_sensor = self._has_light_sensor()
67585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        has_hover = self._has_hover_detection()
67685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        # TODO(ravisadineni):if (crbug: 603233) becomes default
67785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        # change this to reflect it.
67885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        if has_light_sensor and has_hover:
67985dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            level_to_set = (30 * default_level) / 100
68085dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        elif has_light_sensor:
68185dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            level_to_set = (40 * default_level) / 100
68285dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        elif has_hover:
68385dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            logging.warn('Device has hover but no light sensor')
68485dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni
68585dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        logging.info('Setting keyboard backlight to %d', level_to_set)
68685dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        self._keyboard_backlight.set_level(level_to_set)
68785dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni        self._tmp_keyvals['percent_kbd_backlight'] = \
68885dad304a61986ebeff63f749b5b307d152d74a5Ravi Chandra Sadineni            self._keyboard_backlight.get_percent()
6897c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon
6907c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillondef _extension_log_handler(handler, form, loop_number):
6917c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    """
6927c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    We use the httpd library to allow us to log whatever we
6937c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    want from the extension JS script into the log files.
6947c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon
6957c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    This method is provided to the server as a handler for
6967c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    all requests that come for the log url in the testServer
6977c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon
6987c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    unused parameter, because httpd passes the server itself
6997c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    into the handler.
7007c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    """
7017c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon    if form:
7027c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon        for field in form.keys():
703ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            logging.debug("[extension] @ loop_%d %s", loop_number,
704ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            form[field].value)
7057c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # we don't want to add url information to our keyvals.
7067c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            # httpd adds them automatically so we remove them again
7077c5ed505418980be00d6f5770ec6e5aa67b059ffRuben Rodriguez Buchillon            del handler.server._form_entries[field]
708ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
709ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillondef _extension_page_load_info_handler(handler, form, loop_number, tracker):
710ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    stats_ids = ['mean', 'min', 'max', 'std']
711ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    time_measurements = []
712ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    sorted_pagelt = []
713ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    #show up to this number of slow page-loads
714ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    num_slow_page_loads = 5;
715ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
716ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    if not form:
717ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        logging.debug("no page load information returned")
718ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        return;
719ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
720ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    for field in form.keys():
721ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        url = field[str.find(field, "http"):]
722ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        load_time = int(form[field].value)
723ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
724ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        time_measurements.append(load_time)
725ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        sorted_pagelt.append((url, load_time))
726ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
727f364c1d04857e2f5bd20eb5fed2500cf81fbbdbeRuben Rodriguez Buchillon        logging.debug("[extension] @ loop_%d url: %s load time: %d ms",
728ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon            loop_number, url, load_time)
729ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        # we don't want to add url information to our keyvals.
730ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        # httpd adds them automatically so we remove them again
731ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        del handler.server._form_entries[field]
732ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
733ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    time_measurements = numpy.array(time_measurements)
734ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    stats_vals = [time_measurements.mean(), time_measurements.min(),
735ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    time_measurements.max(),time_measurements.std()]
736ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
737ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    key_base = 'ext_ms_page_load_time_'
738ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    for i in range(len(stats_ids)):
739ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        key = key_base + stats_ids[i]
740ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        if key in tracker._tmp_keyvals:
741f364c1d04857e2f5bd20eb5fed2500cf81fbbdbeRuben Rodriguez Buchillon            tracker._tmp_keyvals[key] += "_%.2f" % stats_vals[i]
742ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        else:
743f364c1d04857e2f5bd20eb5fed2500cf81fbbdbeRuben Rodriguez Buchillon            tracker._tmp_keyvals[key] = "%.2f" % stats_vals[i]
744ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
745ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
746ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    sorted_pagelt.sort(key=lambda item: item[1], reverse=True)
747ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
748ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    message = "The %d slowest page-load-times are:\n" % (num_slow_page_loads)
749ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon    for url, msecs in sorted_pagelt[:num_slow_page_loads]:
750ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon        message += "\t%s w/ %d ms" % (url, msecs)
751ca1c3f354eb0a925742c2bac0473b79db1df241aRuben Rodriguez Buchillon
752f364c1d04857e2f5bd20eb5fed2500cf81fbbdbeRuben Rodriguez Buchillon    logging.debug("%s\n", message)
753