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