1# Copyright 2014 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, threading, time 6 7from autotest_lib.client.bin import utils 8from autotest_lib.client.cros import service_stopper 9 10 11class PerfControl(object): 12 """ 13 Provides methods for setting the performance mode of a device. 14 15 In particular it verifies the machine is idle and cold and tries to set 16 it into a consistent, high performance state during initialization. 17 18 Furthermore it monitors the state of the machine (in particular 19 temperature) and verifies that nothing bad happened along the way. 20 21 Example usage: 22 23 with PerfControl() as pc: 24 if not pc.verify_is_valid(): 25 raise error.TestError(pc.get_error_reason()) 26 # Do all performance testing. 27 ... 28 if not pc.verify_is_valid(): 29 raise error.TestError(pc.get_error_reason()) 30 """ 31 def __init__(self): 32 self._service_stopper = None 33 # Keep a copy of the current state for cleanup. 34 self._temperature_init = utils.get_current_temperature_max() 35 self._throttle_count = 0 36 self._original_governors = utils.set_high_performance_mode() 37 self._error_reason = None 38 if not utils.wait_for_idle_cpu(60.0, 0.1): 39 self._error_reason = 'Could not get idle CPU.' 40 return 41 if not utils.wait_for_cool_machine(): 42 self._error_reason = 'Could not get cold machine.' 43 return 44 self._temperature_cold = utils.get_current_temperature_max() 45 self._temperature_max = self._temperature_cold 46 threading.Thread(target=self._monitor_performance_state).start() 47 # Should be last just in case we had a runaway process. 48 self._stop_thermal_throttling() 49 50 51 def __enter__(self): 52 return self 53 54 55 def __exit__(self, _type, value, traceback): 56 # First thing restart thermal management. 57 self._restore_thermal_throttling() 58 utils.restore_scaling_governor_states(self._original_governors) 59 60 61 def get_error_reason(self): 62 """ 63 Returns an error reason string if we encountered problems to pass 64 on to harness/wmatrix. 65 """ 66 return self._error_reason 67 68 69 def verify_is_valid(self): 70 """ 71 For now we declare performance results as valid if 72 - we did not have an error before. 73 - the monitoring thread never saw temperatures a throttle 74 75 TODO(ihf): Search log files for thermal throttling messages like in 76 src/build/android/pylib/perf/thermal_throttle.py 77 """ 78 if self._error_reason: 79 return False 80 logging.info("Max observed temperature = %.1f'C (throttle_count=%d)", 81 self._temperature_max, self._throttle_count) 82 if (self._throttle_count): 83 self._error_reason = 'Machine got hot during testing.' 84 return False 85 return True 86 87 88 def _monitor_performance_state(self): 89 """ 90 Checks machine temperature once per second. 91 TODO(ihf): make this more intelligent with regards to governor, 92 CPU, GPU and maybe zram as needed. 93 """ 94 while True: 95 time.sleep(1) 96 current_temperature = utils.get_current_temperature_max() 97 self._temperature_max = max(self._temperature_max, 98 current_temperature) 99 is_throttled = utils.is_system_thermally_throttled() 100 if is_throttled: 101 self._throttle_count += 1 102 103 # TODO(ihf): Remove this spew once PerfControl is stable. 104 logging.info('PerfControl system temperature = %.1f, throttled=%s', 105 current_temperature, is_throttled) 106 107 108 def _stop_thermal_throttling(self): 109 """ 110 If exist on the platform/machine it stops the different thermal 111 throttling scripts from running. 112 Warning: this risks abnormal behavior if machine runs in high load. 113 """ 114 self._service_stopper = service_stopper.get_thermal_service_stopper() 115 self._service_stopper.stop_services() 116 117 118 def _restore_thermal_throttling(self): 119 """ 120 Restores the original thermal throttling state. 121 """ 122 if self._service_stopper: 123 self._service_stopper.restore_services() 124