• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5import logging, time
6
7from autotest_lib.client.bin import utils
8from autotest_lib.client.common_lib.cros import chrome
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.cros import service_stopper
11from autotest_lib.client.cros.graphics import graphics_utils
12from autotest_lib.client.cros.power import power_rapl
13from autotest_lib.client.cros.power import power_status
14from autotest_lib.client.cros.power import power_utils
15
16TEST_NAME_AND_FLAGS = [
17    ['hw_overlays_hw_decode', ['']],
18    ['no_overlays_hw_decode', ['--enable-hardware-overlays=']],
19    ['hw_overlays_sw_decode', ['--disable-accelerated-video-decode']],
20    [
21        'no_overlays_sw_decode',
22        ['--disable-accelerated-video-decode', '--enable-hardware-overlays=']
23    ]
24]
25# Amount of time to wait for the URL to load and the video to start playing.
26PREAMBLE_DURATION_SECONDS = 8
27# Amount of time to let the video play while measuring power consumption.
28MEASUREMENT_DURATION_SECONDS = 12
29
30# Time in seconds to wait for cpu idle until giveup.
31IDLE_CPU_WAIT_TIMEOUT_SECONDS = 60.0
32# Maximum percent of cpu usage considered as idle.
33IDLE_CPU_LOAD_PERCENTAGE = 2.5
34
35GRAPH_NAME = 'power_consumption'
36
37
38class graphics_VideoRenderingPower(graphics_utils.GraphicsTest):
39    """This test renders on screen for a short while a video from a given
40
41    (controlled) URL while measuring the power consumption of the different SoC
42    domains.
43    """
44    version = 1
45    _backlight = None
46    _service_stopper = None
47    _power_status = None
48
49    def initialize(self):
50        super(graphics_VideoRenderingPower, self).initialize()
51
52        self._backlight = power_utils.Backlight()
53        self._backlight.set_default()
54
55        self._service_stopper = service_stopper.ServiceStopper(
56            service_stopper.ServiceStopper.POWER_DRAW_SERVICES)
57        self._service_stopper.stop_services()
58
59        self._power_status = power_status.get_status()
60
61    def cleanup(self):
62        if self._backlight:
63            self._backlight.restore()
64        if self._service_stopper:
65            self._service_stopper.restore_services()
66        super(graphics_VideoRenderingPower, self).cleanup()
67
68    @graphics_utils.GraphicsTest.failure_report_decorator(
69        'graphics_VideoRenderingPower')
70    def run_once(self, video_url, video_short_name):
71        """Runs the graphics_VideoRenderingPower test.
72
73        @param video_url: URL with autoplay video inside. It's assumed that
74                 there's just one <video> in the HTML, and that it fits in the
75                 viewport.
76        @param video_short_name: short string describing the video; itt will be
77                 presented as part of the dashboard entry name.
78        """
79
80        # TODO(mcasas): Extend this test to non-Intel platforms.
81        if not power_utils.has_rapl_support():
82            logging.warning('This board has no RAPL power measurement support, '
83                            'skipping test.')
84            return
85
86        rapl = []
87        if power_utils.has_battery():
88            # Sometimes, the DUT is supposed to have a battery but we may not
89            # detect one. This is a symptom of a bad battery (b/145144707).
90            if self._power_status.battery_path is None:
91                raise error.TestFail('No battery found in this DUT (this is a '
92                                     'symptom of a bad battery).')
93            rapl.append(
94                power_status.SystemPower(self._power_status.battery_path))
95        else:
96            logging.warning('This board has no battery.')
97        rapl += power_rapl.create_rapl()
98
99        for test_name_and_flags in TEST_NAME_AND_FLAGS:
100            logging.info('Test case: %s', test_name_and_flags[0])
101            # Launch Chrome with the appropriate flag combination.
102            with chrome.Chrome(
103                    extra_browser_args=test_name_and_flags[1],
104                    init_network_controller=True) as cr:
105
106                if not utils.wait_for_idle_cpu(IDLE_CPU_WAIT_TIMEOUT_SECONDS,
107                                               IDLE_CPU_LOAD_PERCENTAGE):
108                    raise error.TestFail('Failed: Could not get idle CPU.')
109                if not utils.wait_for_cool_machine():
110                    raise error.TestFail('Failed: Could not get cold machine.')
111
112                tab = cr.browser.tabs[0]
113                tab.Navigate(video_url)
114                tab.WaitForDocumentReadyStateToBeComplete()
115                tab.EvaluateJavaScript(
116                    'document.'
117                    'getElementsByTagName(\'video\')[0].scrollIntoView(true)')
118
119                # Disabling hardware overlays is difficult because the flag is
120                # already in the browser. Instead, scroll a bit down to make the
121                # video bleed out of the viewport.
122                if '--enable-hardware-overlays=' in test_name_and_flags[1]:
123                    tab.EvaluateJavaScript('window.scrollBy(0, 1)')
124
125                power_logger = power_status.PowerLogger(rapl)
126                power_logger.start()
127                time.sleep(PREAMBLE_DURATION_SECONDS)
128
129                start_time = time.time()
130                time.sleep(MEASUREMENT_DURATION_SECONDS)
131                power_logger.checkpoint('result', start_time)
132
133                measurements = power_logger.calc()
134                logging.debug(measurements)
135
136                for category in sorted(measurements):
137                    if category.endswith('_pwr_avg'):
138                        description = '%s_%s_%s' % (
139                            video_short_name, test_name_and_flags[0], category)
140                        self.output_perf_value(
141                            description=description,
142                            value=measurements[category],
143                            units='W',
144                            higher_is_better=False,
145                            graph=GRAPH_NAME)
146
147                    if category.endswith('_pwr_avg'):
148                        # write_perf_keyval() wants units (W) first in lowercase.
149                        description = '%s_%s_%s' % (
150                            video_short_name, test_name_and_flags[0], category)
151                        self.write_perf_keyval({
152                            'w_' + description: measurements[category]
153                        })
154