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._temperature_critical = utils.get_temperature_critical() 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 too close to critical. 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 temperature_bad = self._temperature_critical - 1.0 81 logging.info("Max observed temperature = %.1f'C (bad limit = %.1f'C)", 82 self._temperature_max, temperature_bad) 83 if (self._temperature_max > temperature_bad): 84 self._error_reason = 'Machine got hot during testing.' 85 return False 86 return True 87 88 89 def _monitor_performance_state(self): 90 """ 91 Checks machine temperature once per second. 92 TODO(ihf): make this more intelligent with regards to governor, 93 CPU, GPU and maybe zram as needed. 94 """ 95 while True: 96 time.sleep(1) 97 current_temperature = utils.get_current_temperature_max() 98 self._temperature_max = max(self._temperature_max, 99 current_temperature) 100 # TODO(ihf): Remove this spew once PerfControl is stable. 101 logging.info('PerfControl CPU temperature = %.1f', 102 current_temperature) 103 104 105 def _stop_thermal_throttling(self): 106 """ 107 If exist on the platform/machine it stops the different thermal 108 throttling scripts from running. 109 Warning: this risks abnormal behavior if machine runs in high load. 110 """ 111 self._service_stopper = service_stopper.get_thermal_service_stopper() 112 self._service_stopper.stop_services() 113 114 115 def _restore_thermal_throttling(self): 116 """ 117 Restores the original thermal throttling state. 118 """ 119 if self._service_stopper: 120 self._service_stopper.restore_services() 121