1# Copyright 2013 The Chromium 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
6
7
8class OmapThrottlingDetector(object):
9  """Class to detect and track thermal throttling on an OMAP 4."""
10  OMAP_TEMP_FILE = ('/sys/devices/platform/omap/omap_temp_sensor.0/'
11                    'temperature')
12
13  @staticmethod
14  def IsSupported(device):
15    return device.FileExists(OmapThrottlingDetector.OMAP_TEMP_FILE)
16
17  def __init__(self, device):
18    self._device = device
19
20  @staticmethod
21  def BecameThrottled(log_line):
22    return 'omap_thermal_throttle' in log_line
23
24  @staticmethod
25  def BecameUnthrottled(log_line):
26    return 'omap_thermal_unthrottle' in log_line
27
28  @staticmethod
29  def GetThrottlingTemperature(log_line):
30    if 'throttle_delayed_work_fn' in log_line:
31      return float([s for s in log_line.split() if s.isdigit()][0]) / 1000.0
32
33  def GetCurrentTemperature(self):
34    tempdata = self._device.ReadFile(OmapThrottlingDetector.OMAP_TEMP_FILE)
35    return float(tempdata) / 1000.0
36
37
38class ExynosThrottlingDetector(object):
39  """Class to detect and track thermal throttling on an Exynos 5."""
40  @staticmethod
41  def IsSupported(device):
42    return device.FileExists('/sys/bus/exynos5-core')
43
44  def __init__(self, device):
45    pass
46
47  @staticmethod
48  def BecameThrottled(log_line):
49    return 'exynos_tmu: Throttling interrupt' in log_line
50
51  @staticmethod
52  def BecameUnthrottled(log_line):
53    return 'exynos_thermal_unthrottle: not throttling' in log_line
54
55  @staticmethod
56  def GetThrottlingTemperature(_log_line):
57    return None
58
59  @staticmethod
60  def GetCurrentTemperature():
61    return None
62
63
64class ThermalThrottle(object):
65  """Class to detect and track thermal throttling.
66
67  Usage:
68    Wait for IsThrottled() to be False before running test
69    After running test call HasBeenThrottled() to find out if the
70    test run was affected by thermal throttling.
71  """
72
73  def __init__(self, device):
74    self._device = device
75    self._throttled = False
76    self._detector = None
77    if OmapThrottlingDetector.IsSupported(device):
78      self._detector = OmapThrottlingDetector(device)
79    elif ExynosThrottlingDetector.IsSupported(device):
80      self._detector = ExynosThrottlingDetector(device)
81
82  def HasBeenThrottled(self):
83    """True if there has been any throttling since the last call to
84       HasBeenThrottled or IsThrottled.
85    """
86    return self._ReadLog()
87
88  def IsThrottled(self):
89    """True if currently throttled."""
90    self._ReadLog()
91    return self._throttled
92
93  def _ReadLog(self):
94    if not self._detector:
95      return False
96    has_been_throttled = False
97    serial_number = str(self._device)
98    log = self._device.RunShellCommand('dmesg -c')
99    degree_symbol = unichr(0x00B0)
100    for line in log:
101      if self._detector.BecameThrottled(line):
102        if not self._throttled:
103          logging.warning('>>> Device %s thermally throttled', serial_number)
104        self._throttled = True
105        has_been_throttled = True
106      elif self._detector.BecameUnthrottled(line):
107        if self._throttled:
108          logging.warning('>>> Device %s thermally unthrottled', serial_number)
109        self._throttled = False
110        has_been_throttled = True
111      temperature = self._detector.GetThrottlingTemperature(line)
112      if temperature is not None:
113        logging.info(u'Device %s thermally throttled at %3.1f%sC',
114                     serial_number, temperature, degree_symbol)
115
116    if logging.getLogger().isEnabledFor(logging.DEBUG):
117      # Print current temperature of CPU SoC.
118      temperature = self._detector.GetCurrentTemperature()
119      if temperature is not None:
120        logging.debug(u'Current SoC temperature of %s = %3.1f%sC',
121                      serial_number, temperature, degree_symbol)
122
123      # Print temperature of battery, to give a system temperature
124      dumpsys_log = self._device.RunShellCommand('dumpsys battery')
125      for line in dumpsys_log:
126        if 'temperature' in line:
127          btemp = float([s for s in line.split() if s.isdigit()][0]) / 10.0
128          logging.debug(u'Current battery temperature of %s = %3.1f%sC',
129                        serial_number, btemp, degree_symbol)
130
131    return has_been_throttled
132
133