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