1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import logging
6a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom pylib import android_commands
7a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom pylib.device import device_utils
8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class OmapThrottlingDetector(object):
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """Class to detect and track thermal throttling on an OMAP 4."""
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OMAP_TEMP_FILE = ('/sys/devices/platform/omap/omap_temp_sensor.0/'
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                    'temperature')
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  @staticmethod
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def IsSupported(device):
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return device.FileExists(OmapThrottlingDetector.OMAP_TEMP_FILE)
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def __init__(self, device):
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    self._device = device
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def BecameThrottled(log_line):
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 'omap_thermal_throttle' in log_line
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def BecameUnthrottled(log_line):
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 'omap_thermal_unthrottle' in log_line
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetThrottlingTemperature(log_line):
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if 'throttle_delayed_work_fn' in log_line:
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return float([s for s in log_line.split() if s.isdigit()][0]) / 1000.0
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def GetCurrentTemperature(self):
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    tempdata = self._device.ReadFile(OmapThrottlingDetector.OMAP_TEMP_FILE)
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return float(tempdata[0]) / 1000.0
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class ExynosThrottlingDetector(object):
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  """Class to detect and track thermal throttling on an Exynos 5."""
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  @staticmethod
43a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def IsSupported(device):
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return device.FileExists('/sys/bus/exynos5-core')
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
46a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def __init__(self, device):
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    pass
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def BecameThrottled(log_line):
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 'exynos_tmu: Throttling interrupt' in log_line
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def BecameUnthrottled(log_line):
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 'exynos_thermal_unthrottle: not throttling' in log_line
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetThrottlingTemperature(_log_line):
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return None
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @staticmethod
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetCurrentTemperature():
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return None
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class ThermalThrottle(object):
67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """Class to detect and track thermal throttling.
68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Usage:
70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    Wait for IsThrottled() to be False before running test
71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    After running test call HasBeenThrottled() to find out if the
72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    test run was affected by thermal throttling.
73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  """
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
75a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def __init__(self, device):
76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # TODO(jbudorick) Remove once telemetry gets switched over.
77a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if isinstance(device, android_commands.AndroidCommands):
78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      device = device_utils.DeviceUtils(device)
79a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    self._device = device
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    self._throttled = False
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._detector = None
82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if OmapThrottlingDetector.IsSupported(device):
83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      self._detector = OmapThrottlingDetector(device)
84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    elif ExynosThrottlingDetector.IsSupported(device):
85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      self._detector = ExynosThrottlingDetector(device)
86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  def HasBeenThrottled(self):
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    """True if there has been any throttling since the last call to
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       HasBeenThrottled or IsThrottled.
90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    """
91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return self._ReadLog()
92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  def IsThrottled(self):
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    """True if currently throttled."""
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    self._ReadLog()
96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return self._throttled
97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  def _ReadLog(self):
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if not self._detector:
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return False
101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    has_been_throttled = False
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    serial_number = str(self._device)
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    log = self._device.RunShellCommand('dmesg -c')
104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    degree_symbol = unichr(0x00B0)
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    for line in log:
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if self._detector.BecameThrottled(line):
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if not self._throttled:
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          logging.warning('>>> Device %s thermally throttled', serial_number)
109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        self._throttled = True
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        has_been_throttled = True
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      elif self._detector.BecameUnthrottled(line):
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if self._throttled:
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          logging.warning('>>> Device %s thermally unthrottled', serial_number)
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        self._throttled = False
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        has_been_throttled = True
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      temperature = self._detector.GetThrottlingTemperature(line)
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if temperature is not None:
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        logging.info(u'Device %s thermally throttled at %3.1f%sC',
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     serial_number, temperature, degree_symbol)
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if logging.getLogger().isEnabledFor(logging.DEBUG):
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      # Print current temperature of CPU SoC.
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      temperature = self._detector.GetCurrentTemperature()
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if temperature is not None:
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        logging.debug(u'Current SoC temperature of %s = %3.1f%sC',
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      serial_number, temperature, degree_symbol)
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      # Print temperature of battery, to give a system temperature
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      dumpsys_log = self._device.RunShellCommand('dumpsys battery')
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      for line in dumpsys_log:
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if 'temperature' in line:
132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          btemp = float([s for s in line.split() if s.isdigit()][0]) / 10.0
133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          logging.debug(u'Current battery temperature of %s = %3.1f%sC',
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                        serial_number, btemp, degree_symbol)
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return has_been_throttled
137a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
138