• 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
6import threading
7import time
8
9from autotest_lib.client.bin import utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros import chrome_binary_test
12from autotest_lib.client.cros import service_stopper
13from autotest_lib.client.cros.power import power_status
14from autotest_lib.client.cros.power import power_utils
15from autotest_lib.client.cros.video import helper_logger
16
17DECODE_WITH_HW_ACCELERATION = 'jpeg_decode_with_hw'
18DECODE_WITHOUT_HW_ACCELERATION = 'jpeg_decode_with_sw'
19
20# Measurement duration in seconds.
21MEASUREMENT_DURATION = 10
22
23# List of thermal throttling services that should be disabled.
24# - temp_metrics for link.
25# - thermal for daisy, snow, pit etc.
26THERMAL_SERVICES = ['temp_metrics', 'thermal']
27
28# Time in seconds to wait for cpu idle until giveup.
29WAIT_FOR_IDLE_CPU_TIMEOUT = 60.0
30# Maximum percent of cpu usage considered as idle.
31CPU_IDLE_USAGE = 0.1
32
33# Minimum battery charge percentage to run the test
34BATTERY_INITIAL_CHARGED_MIN = 10
35
36
37class video_JDAPerf(chrome_binary_test.ChromeBinaryTest):
38    """
39    The test outputs the cpu usage and the power consumption for jpeg decoding
40    to performance dashboard.
41    """
42    version = 1
43
44    # Decoding times for performance measurement
45    perf_jpeg_decode_times = 600
46
47    binary = 'jpeg_decode_accelerator_unittest'
48    jda_filter = 'JpegDecodeAcceleratorTest.PerfJDA'
49    sw_filter = 'JpegDecodeAcceleratorTest.PerfSW'
50
51    def initialize(self):
52        """Initialize this test."""
53        super(video_JDAPerf, self).initialize()
54        self._service_stopper = None
55        self._original_governors = None
56        self._backlight = None
57        self._use_ec = False
58
59    @chrome_binary_test.nuke_chrome
60    def run_once(self, power_test=False):
61        """
62        Runs the video_JDAPerf test.
63
64        @param power_test: True for power consumption test.
65                           False for cpu usage test.
66        """
67        if power_test:
68            keyvals = self.test_power()
69            self.log_result(keyvals, 'jpeg_decode_energy', 'W')
70        else:
71            keyvals = self.test_cpu_usage()
72            self.log_result(keyvals, 'jpeg_decode_cpu', 'percent')
73
74    def test_cpu_usage(self):
75        """
76        Runs the video cpu usage test.
77
78        @return a dictionary that contains the test result.
79        """
80        def get_cpu_usage():
81            cpu_usage_start = utils.get_cpu_usage()
82            time.sleep(MEASUREMENT_DURATION)
83            cpu_usage_end = utils.get_cpu_usage()
84            return utils.compute_active_cpu_time(cpu_usage_start,
85                                                 cpu_usage_end) * 100
86
87        # crbug/753292 - APNG login pictures increase CPU usage. Move the more
88        # strict idle checks after the login phase.
89        if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
90                                       CPU_IDLE_USAGE):
91            logging.warning('Could not get idle CPU pre login.')
92        if not utils.wait_for_cool_machine():
93            logging.warning('Could not get cold machine pre login.')
94
95        # Stop the thermal service that may change the cpu frequency.
96        self._service_stopper = service_stopper.ServiceStopper(THERMAL_SERVICES)
97        self._service_stopper.stop_services()
98        # Set the scaling governor to performance mode to set the cpu to the
99        # highest frequency available.
100        self._original_governors = utils.set_high_performance_mode()
101        return self.test_decode(get_cpu_usage)
102
103    def test_power(self):
104        """
105        Runs the video power consumption test.
106
107        @return a dictionary that contains the test result.
108        """
109
110        self._backlight = power_utils.Backlight()
111        self._backlight.set_level(0)
112
113        self._power_status = power_status.get_status()
114
115        self._use_ec = True
116        if not power_utils.charge_control_by_ectool(is_charge=False):
117            logging.warning('Can\'t stop charging')
118            return {}
119
120        if not self._power_status.battery:
121            raise error.TestFail('No valid battery')
122
123        # Verify that the battery is sufficiently charged.
124        percent_initial_charge = self._power_status.percent_current_charge()
125        if percent_initial_charge < BATTERY_INITIAL_CHARGED_MIN:
126            logging.warning('Initial charge (%f) less than min (%f)',
127                            (percent_initial_charge,
128                             BATTERY_INITIAL_CHARGED_MIN))
129            return {}
130
131        measurements = [power_status.SystemPower(
132                self._power_status.battery_path)]
133
134        def get_power():
135            power_logger = power_status.PowerLogger(measurements)
136            power_logger.start()
137            start_time = time.time()
138            time.sleep(MEASUREMENT_DURATION)
139            power_logger.checkpoint('result', start_time)
140            keyval = power_logger.calc()
141            return keyval['result_' + measurements[0].domain + '_pwr_avg']
142
143        return self.test_decode(get_power)
144
145    def start_decode(self, gtest_filter):
146        """
147        Start jpeg decode process.
148
149        @param gtest_filter: gtest_filter argument.
150        """
151        logging.debug('Starting video_JpegDecodeAccelerator %s', gtest_filter)
152        cmd_line_list = [helper_logger.chrome_vmodule_flag()]
153        cmd_line_list.append('--gtest_filter="%s"' % gtest_filter)
154        cmd_line_list.append('--perf_decode_times=%d' %
155                             self.perf_jpeg_decode_times)
156
157        cmd_line = ' '.join(cmd_line_list)
158        self.run_chrome_test_binary(self.binary, cmd_line)
159
160    def test_decode(self, gather_result):
161        """
162        Runs the jpeg decode test with and without hardware acceleration.
163
164        @param gather_result: a function to run and return the test result
165
166        @return a dictionary that contains test the result.
167        """
168        keyvals = {}
169
170        thread = threading.Thread(target=self.start_decode,
171                                  kwargs={'gtest_filter': self.jda_filter})
172        thread.start()
173        result = gather_result()
174        thread.join()
175        keyvals[DECODE_WITH_HW_ACCELERATION] = result
176
177        thread = threading.Thread(target=self.start_decode,
178                                  kwargs={'gtest_filter': self.sw_filter})
179        thread.start()
180        result = gather_result()
181        thread.join()
182        keyvals[DECODE_WITHOUT_HW_ACCELERATION] = result
183
184        return keyvals
185
186    def log_result(self, keyvals, description, units):
187        """
188        Logs the test result output to the performance dashboard.
189
190        @param keyvals: a dictionary that contains results returned by
191                test_playback.
192        @param description: a string that describes the video and test result
193                and it will be part of the entry name in the dashboard.
194        @param units: the units of test result.
195        """
196        result_with_hw = keyvals.get(DECODE_WITH_HW_ACCELERATION)
197        if result_with_hw is not None:
198            self.output_perf_value(description='hw_' + description,
199                                   value=result_with_hw,
200                                   units=units, higher_is_better=False)
201
202        result_without_hw = keyvals.get(DECODE_WITHOUT_HW_ACCELERATION)
203        if result_without_hw is not None:
204            self.output_perf_value(
205                    description='sw_' + description, value=result_without_hw,
206                    units=units, higher_is_better=False)
207
208    def cleanup(self):
209        """Autotest cleanup function
210
211        It is run by common_lib/test.py.
212        """
213        if self._backlight:
214            self._backlight.restore()
215        if self._service_stopper:
216            self._service_stopper.restore_services()
217        if self._original_governors:
218            utils.restore_scaling_governor_states(self._original_governors)
219        if self._use_ec:
220            power_utils.charge_control_by_ectool(is_charge=True)
221        super(video_JDAPerf, self).cleanup()
222