• 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._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