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