• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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