Home | History | Annotate | Download | only in cros
      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 
      5 import logging, threading, time
      6 
      7 from autotest_lib.client.bin import utils
      8 from autotest_lib.client.cros import service_stopper
      9 
     10 
     11 class 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