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 6import os 7import subprocess 8import sys 9 10from telemetry import decorators 11from telemetry.core.platform import linux_based_platform_backend 12from telemetry.core.platform import platform_backend 13from telemetry.core.platform import posix_platform_backend 14from telemetry.core.platform.power_monitor import msr_power_monitor 15from telemetry.util import cloud_storage 16from telemetry.util import support_binaries 17 18 19_POSSIBLE_PERFHOST_APPLICATIONS = [ 20 'perfhost_precise', 21 'perfhost_trusty', 22] 23 24 25class LinuxPlatformBackend( 26 posix_platform_backend.PosixPlatformBackend, 27 linux_based_platform_backend.LinuxBasedPlatformBackend): 28 def __init__(self): 29 super(LinuxPlatformBackend, self).__init__() 30 self._power_monitor = msr_power_monitor.MsrPowerMonitor(self) 31 32 def StartRawDisplayFrameRateMeasurement(self): 33 raise NotImplementedError() 34 35 def StopRawDisplayFrameRateMeasurement(self): 36 raise NotImplementedError() 37 38 def GetRawDisplayFrameRateMeasurements(self): 39 raise NotImplementedError() 40 41 def IsThermallyThrottled(self): 42 raise NotImplementedError() 43 44 def HasBeenThermallyThrottled(self): 45 raise NotImplementedError() 46 47 def GetOSName(self): 48 return 'linux' 49 50 @decorators.Cache 51 def GetOSVersionName(self): 52 if not os.path.exists('/etc/lsb-release'): 53 raise NotImplementedError('Unknown Linux OS version') 54 55 codename = None 56 version = None 57 for line in self.GetFileContents('/etc/lsb-release').splitlines(): 58 key, _, value = line.partition('=') 59 if key == 'DISTRIB_CODENAME': 60 codename = value.strip() 61 elif key == 'DISTRIB_RELEASE': 62 try: 63 version = float(value) 64 except ValueError: 65 version = 0 66 if codename and version: 67 break 68 return platform_backend.OSVersion(codename, version) 69 70 def CanFlushIndividualFilesFromSystemCache(self): 71 return True 72 73 def FlushEntireSystemCache(self): 74 p = subprocess.Popen(['/sbin/sysctl', '-w', 'vm.drop_caches=3']) 75 p.wait() 76 assert p.returncode == 0, 'Failed to flush system cache' 77 78 def CanLaunchApplication(self, application): 79 if application == 'ipfw' and not self._IsIpfwKernelModuleInstalled(): 80 return False 81 return super(LinuxPlatformBackend, self).CanLaunchApplication(application) 82 83 def InstallApplication(self, application): 84 if application == 'ipfw': 85 self._InstallIpfw() 86 elif application == 'avconv': 87 self._InstallBinary(application, fallback_package='libav-tools') 88 elif application in _POSSIBLE_PERFHOST_APPLICATIONS: 89 self._InstallBinary(application) 90 else: 91 raise NotImplementedError( 92 'Please teach Telemetry how to install ' + application) 93 94 def CanMonitorPower(self): 95 return self._power_monitor.CanMonitorPower() 96 97 def CanMeasurePerApplicationPower(self): 98 return self._power_monitor.CanMeasurePerApplicationPower() 99 100 def StartMonitoringPower(self, browser): 101 self._power_monitor.StartMonitoringPower(browser) 102 103 def StopMonitoringPower(self): 104 return self._power_monitor.StopMonitoringPower() 105 106 def ReadMsr(self, msr_number, start=0, length=64): 107 cmd = ['/usr/sbin/rdmsr', '-d', str(msr_number)] 108 (out, err) = subprocess.Popen(cmd, 109 stdout=subprocess.PIPE, 110 stderr=subprocess.PIPE).communicate() 111 if err: 112 raise OSError(err) 113 try: 114 result = int(out) 115 except ValueError: 116 raise OSError('Cannot interpret rdmsr output: %s' % out) 117 return result >> start & ((1 << length) - 1) 118 119 def _IsIpfwKernelModuleInstalled(self): 120 return 'ipfw_mod' in subprocess.Popen( 121 ['lsmod'], stdout=subprocess.PIPE).communicate()[0] 122 123 def _InstallIpfw(self): 124 ipfw_bin = support_binaries.FindPath('ipfw', self.GetOSName()) 125 ipfw_mod = support_binaries.FindPath('ipfw_mod.ko', self.GetOSName()) 126 127 try: 128 changed = cloud_storage.GetIfChanged( 129 ipfw_bin, cloud_storage.INTERNAL_BUCKET) 130 changed |= cloud_storage.GetIfChanged( 131 ipfw_mod, cloud_storage.INTERNAL_BUCKET) 132 except cloud_storage.CloudStorageError, e: 133 logging.error(str(e)) 134 logging.error('You may proceed by manually building and installing' 135 'dummynet for your kernel. See: ' 136 'http://info.iet.unipi.it/~luigi/dummynet/') 137 sys.exit(1) 138 139 if changed or not self.CanLaunchApplication('ipfw'): 140 if not self._IsIpfwKernelModuleInstalled(): 141 subprocess.check_call(['sudo', 'insmod', ipfw_mod]) 142 os.chmod(ipfw_bin, 0755) 143 subprocess.check_call(['sudo', 'cp', ipfw_bin, '/usr/local/sbin']) 144 145 assert self.CanLaunchApplication('ipfw'), 'Failed to install ipfw. ' \ 146 'ipfw provided binaries are not supported for linux kernel < 3.13. ' \ 147 'You may proceed by manually building and installing dummynet for ' \ 148 'your kernel. See: http://info.iet.unipi.it/~luigi/dummynet/' 149 150 def _InstallBinary(self, bin_name, fallback_package=None): 151 bin_path = support_binaries.FindPath(bin_name, self.GetOSName()) 152 if not bin_path: 153 raise Exception('Could not find the binary package %s' % bin_name) 154 os.environ['PATH'] += os.pathsep + os.path.dirname(bin_path) 155 156 try: 157 cloud_storage.GetIfChanged(bin_path, cloud_storage.INTERNAL_BUCKET) 158 os.chmod(bin_path, 0755) 159 except cloud_storage.CloudStorageError, e: 160 logging.error(str(e)) 161 if fallback_package: 162 raise Exception('You may proceed by manually installing %s via:\n' 163 'sudo apt-get install %s' % 164 (bin_name, fallback_package)) 165 166 assert self.CanLaunchApplication(bin_name), 'Failed to install ' + bin_name 167