1# Copyright 2012 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 as real_logging 6import os 7import sys 8 9from telemetry.core import discover 10from telemetry.core import util 11from telemetry.core.platform import platform_backend as platform_backend_module 12from telemetry.core.platform import profiling_controller 13from telemetry.core.platform import tracing_controller 14 15 16_host_platform = None 17# Remote platform is a dictionary from device ids to remote platform instances. 18_remote_platforms = {} 19 20 21def _IsRunningOnCrosDevice(): 22 """Returns True if we're on a ChromeOS device.""" 23 lsb_release = '/etc/lsb-release' 24 if sys.platform.startswith('linux') and os.path.exists(lsb_release): 25 with open(lsb_release, 'r') as f: 26 res = f.read() 27 if res.count('CHROMEOS_RELEASE_NAME'): 28 return True 29 return False 30 31 32def _InitHostPlatformIfNeeded(): 33 global _host_platform 34 if _host_platform: 35 return 36 if _IsRunningOnCrosDevice(): 37 from telemetry.core.platform import cros_platform_backend 38 backend = cros_platform_backend.CrosPlatformBackend() 39 elif sys.platform.startswith('linux'): 40 from telemetry.core.platform import linux_platform_backend 41 backend = linux_platform_backend.LinuxPlatformBackend() 42 elif sys.platform == 'darwin': 43 from telemetry.core.platform import mac_platform_backend 44 backend = mac_platform_backend.MacPlatformBackend() 45 elif sys.platform == 'win32': 46 from telemetry.core.platform import win_platform_backend 47 backend = win_platform_backend.WinPlatformBackend() 48 else: 49 raise NotImplementedError() 50 51 _host_platform = Platform(backend) 52 53 54def GetHostPlatform(): 55 _InitHostPlatformIfNeeded() 56 return _host_platform 57 58 59def GetPlatformForDevice(device, logging=real_logging): 60 """ Returns a platform instance for the device. 61 Args: 62 device: a device.Device instance. 63 """ 64 if device.guid in _remote_platforms: 65 return _remote_platforms[device.guid] 66 try: 67 platform_backend = None 68 platform_dir = os.path.dirname(os.path.realpath(__file__)) 69 for platform_backend_class in discover.DiscoverClasses( 70 platform_dir, util.GetTelemetryDir(), 71 platform_backend_module.PlatformBackend).itervalues(): 72 if platform_backend_class.SupportsDevice(device): 73 platform_backend = platform_backend_class(device) 74 _remote_platforms[device.guid] = Platform(platform_backend) 75 return _remote_platforms[device.guid] 76 return None 77 except Exception: 78 logging.error('Fail to create platform instance for %s.', device.name) 79 raise 80 81 82class Platform(object): 83 """The platform that the target browser is running on. 84 85 Provides a limited interface to interact with the platform itself, where 86 possible. It's important to note that platforms may not provide a specific 87 API, so check with IsFooBar() for availability. 88 """ 89 def __init__(self, platform_backend): 90 self._platform_backend = platform_backend 91 self._platform_backend.SetPlatform(self) 92 self._tracing_controller = tracing_controller.TracingController( 93 self._platform_backend.tracing_controller_backend) 94 self._profiling_controller = profiling_controller.ProfilingController( 95 self._platform_backend.profiling_controller_backend) 96 97 @property 98 def tracing_controller(self): 99 return self._tracing_controller 100 101 @property 102 def profiling_controller(self): 103 return self._profiling_controller 104 105 def IsRawDisplayFrameRateSupported(self): 106 """Platforms may be able to collect GL surface stats.""" 107 return self._platform_backend.IsRawDisplayFrameRateSupported() 108 109 def StartRawDisplayFrameRateMeasurement(self): 110 """Start measuring GL surface stats.""" 111 return self._platform_backend.StartRawDisplayFrameRateMeasurement() 112 113 def StopRawDisplayFrameRateMeasurement(self): 114 """Stop measuring GL surface stats.""" 115 return self._platform_backend.StopRawDisplayFrameRateMeasurement() 116 117 class RawDisplayFrameRateMeasurement(object): 118 def __init__(self, name, value, unit): 119 self._name = name 120 self._value = value 121 self._unit = unit 122 123 @property 124 def name(self): 125 return self._name 126 127 @property 128 def value(self): 129 return self._value 130 131 @property 132 def unit(self): 133 return self._unit 134 135 def GetRawDisplayFrameRateMeasurements(self): 136 """Returns a list of RawDisplayFrameRateMeasurement.""" 137 return self._platform_backend.GetRawDisplayFrameRateMeasurements() 138 139 def CanMonitorThermalThrottling(self): 140 """Platforms may be able to detect thermal throttling. 141 142 Some fan-less computers go into a reduced performance mode when their heat 143 exceeds a certain threshold. Performance tests in particular should use this 144 API to detect if this has happened and interpret results accordingly. 145 """ 146 return self._platform_backend.CanMonitorThermalThrottling() 147 148 def IsThermallyThrottled(self): 149 """Returns True if the device is currently thermally throttled.""" 150 return self._platform_backend.IsThermallyThrottled() 151 152 def HasBeenThermallyThrottled(self): 153 """Returns True if the device has been thermally throttled.""" 154 return self._platform_backend.HasBeenThermallyThrottled() 155 156 def GetOSName(self): 157 """Returns a string description of the Platform OS. 158 159 Examples: WIN, MAC, LINUX, CHROMEOS""" 160 return self._platform_backend.GetOSName() 161 162 def GetOSVersionName(self): 163 """Returns a logically sortable, string-like description of the Platform OS 164 version. 165 166 Examples: VISTA, WIN7, LION, MOUNTAINLION""" 167 return self._platform_backend.GetOSVersionName() 168 169 def CanFlushIndividualFilesFromSystemCache(self): 170 """Returns true if the disk cache can be flushed for specific files.""" 171 return self._platform_backend.CanFlushIndividualFilesFromSystemCache() 172 173 def FlushEntireSystemCache(self): 174 """Flushes the OS's file cache completely. 175 176 This function may require root or administrator access.""" 177 return self._platform_backend.FlushEntireSystemCache() 178 179 def FlushSystemCacheForDirectory(self, directory, ignoring=None): 180 """Flushes the OS's file cache for the specified directory. 181 182 Any files or directories inside |directory| matching a name in the 183 |ignoring| list will be skipped. 184 185 This function does not require root or administrator access.""" 186 return self._platform_backend.FlushSystemCacheForDirectory( 187 directory, ignoring=ignoring) 188 189 def FlushDnsCache(self): 190 """Flushes the OS's DNS cache completely. 191 192 This function may require root or administrator access.""" 193 return self._platform_backend.FlushDnsCache() 194 195 def LaunchApplication(self, application, parameters=None, 196 elevate_privilege=False): 197 """"Launches the given |application| with a list of |parameters| on the OS. 198 199 Set |elevate_privilege| to launch the application with root or admin rights. 200 201 Returns: 202 A popen style process handle for host platforms. 203 """ 204 return self._platform_backend.LaunchApplication( 205 application, parameters, elevate_privilege=elevate_privilege) 206 207 def IsApplicationRunning(self, application): 208 """Returns whether an application is currently running.""" 209 return self._platform_backend.IsApplicationRunning(application) 210 211 def CanLaunchApplication(self, application): 212 """Returns whether the platform can launch the given application.""" 213 return self._platform_backend.CanLaunchApplication(application) 214 215 def InstallApplication(self, application): 216 """Installs the given application.""" 217 return self._platform_backend.InstallApplication(application) 218 219 def CanCaptureVideo(self): 220 """Returns a bool indicating whether the platform supports video capture.""" 221 return self._platform_backend.CanCaptureVideo() 222 223 def StartVideoCapture(self, min_bitrate_mbps): 224 """Starts capturing video. 225 226 Outer framing may be included (from the OS, browser window, and webcam). 227 228 Args: 229 min_bitrate_mbps: The minimum capture bitrate in MegaBits Per Second. 230 The platform is free to deliver a higher bitrate if it can do so 231 without increasing overhead. 232 233 Raises: 234 ValueError if the required |min_bitrate_mbps| can't be achieved. 235 """ 236 return self._platform_backend.StartVideoCapture(min_bitrate_mbps) 237 238 def StopVideoCapture(self): 239 """Stops capturing video. 240 241 Returns: 242 A telemetry.core.video.Video object. 243 """ 244 return self._platform_backend.StopVideoCapture() 245 246 def CanMonitorPower(self): 247 """Returns True iff power can be monitored asynchronously via 248 StartMonitoringPower() and StopMonitoringPower(). 249 """ 250 return self._platform_backend.CanMonitorPower() 251 252 def CanMeasurePerApplicationPower(self): 253 """Returns True if the power monitor can measure power for the target 254 application in isolation. False if power measurement is for full system 255 energy consumption.""" 256 return self._platform_backend.CanMeasurePerApplicationPower() 257 258 259 def StartMonitoringPower(self, browser): 260 """Starts monitoring power utilization statistics. 261 262 Args: 263 browser: The browser to monitor. 264 """ 265 assert self._platform_backend.CanMonitorPower() 266 self._platform_backend.StartMonitoringPower(browser) 267 268 def StopMonitoringPower(self): 269 """Stops monitoring power utilization and returns stats 270 271 Returns: 272 None if power measurement failed for some reason, otherwise a dict of 273 power utilization statistics containing: { 274 # An identifier for the data provider. Allows to evaluate the precision 275 # of the data. Example values: monsoon, powermetrics, ds2784 276 'identifier': identifier, 277 278 # The instantaneous power (voltage * current) reading in milliwatts at 279 # each sample. 280 'power_samples_mw': [mw0, mw1, ..., mwN], 281 282 # The full system energy consumption during the sampling period in 283 # milliwatt hours. May be estimated by integrating power samples or may 284 # be exact on supported hardware. 285 'energy_consumption_mwh': mwh, 286 287 # The target application's energy consumption during the sampling period 288 # in milliwatt hours. Should be returned iff 289 # CanMeasurePerApplicationPower() return true. 290 'application_energy_consumption_mwh': mwh, 291 292 # A platform-specific dictionary of additional details about the 293 # utilization of individual hardware components. 294 component_utilization: { 295 296 # Platform-specific data not attributed to any particular hardware 297 # component. 298 whole_package: { 299 300 # Device-specific onboard temperature sensor. 301 'average_temperature_c': c, 302 303 ... 304 } 305 306 ... 307 } 308 } 309 """ 310 return self._platform_backend.StopMonitoringPower() 311