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