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