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