diff options
Diffstat (limited to 'catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py')
-rw-r--r-- | catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py b/catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py new file mode 100644 index 00000000..5532d59d --- /dev/null +++ b/catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py @@ -0,0 +1,162 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import os +import platform +import subprocess +import sys + +from py_utils import cloud_storage # pylint: disable=import-error + +from telemetry.internal.util import binary_manager +from telemetry.core import os_version +from telemetry.core import util +from telemetry import decorators +from telemetry.internal.platform import linux_based_platform_backend +from telemetry.internal.platform import posix_platform_backend +from telemetry.internal.platform.power_monitor import msr_power_monitor + + +_POSSIBLE_PERFHOST_APPLICATIONS = [ + 'perfhost_precise', + 'perfhost_trusty', +] + + +class LinuxPlatformBackend( + posix_platform_backend.PosixPlatformBackend, + linux_based_platform_backend.LinuxBasedPlatformBackend): + def __init__(self): + super(LinuxPlatformBackend, self).__init__() + self._power_monitor = msr_power_monitor.MsrPowerMonitorLinux(self) + + @classmethod + def IsPlatformBackendForHost(cls): + return sys.platform.startswith('linux') and not util.IsRunningOnCrosDevice() + + def IsThermallyThrottled(self): + raise NotImplementedError() + + def HasBeenThermallyThrottled(self): + raise NotImplementedError() + + @decorators.Cache + def GetArchName(self): + return platform.machine() + + def GetOSName(self): + return 'linux' + + @decorators.Cache + def GetOSVersionName(self): + if not os.path.exists('/etc/lsb-release'): + raise NotImplementedError('Unknown Linux OS version') + + codename = None + version = None + for line in self.GetFileContents('/etc/lsb-release').splitlines(): + key, _, value = line.partition('=') + if key == 'DISTRIB_CODENAME': + codename = value.strip() + elif key == 'DISTRIB_RELEASE': + try: + version = float(value) + except ValueError: + version = 0 + if codename and version: + break + return os_version.OSVersion(codename, version) + + def CanFlushIndividualFilesFromSystemCache(self): + return True + + def SupportFlushEntireSystemCache(self): + return self.HasRootAccess() + + def FlushEntireSystemCache(self): + p = subprocess.Popen(['/sbin/sysctl', '-w', 'vm.drop_caches=3']) + p.wait() + assert p.returncode == 0, 'Failed to flush system cache' + + def CanLaunchApplication(self, application): + if application == 'ipfw' and not self._IsIpfwKernelModuleInstalled(): + return False + return super(LinuxPlatformBackend, self).CanLaunchApplication(application) + + def InstallApplication(self, application): + if application == 'ipfw': + self._InstallIpfw() + elif application == 'avconv': + self._InstallBinary(application) + elif application in _POSSIBLE_PERFHOST_APPLICATIONS: + self._InstallBinary(application) + else: + raise NotImplementedError( + 'Please teach Telemetry how to install ' + application) + + def CanMonitorPower(self): + return self._power_monitor.CanMonitorPower() + + def CanMeasurePerApplicationPower(self): + return self._power_monitor.CanMeasurePerApplicationPower() + + def StartMonitoringPower(self, browser): + self._power_monitor.StartMonitoringPower(browser) + + def StopMonitoringPower(self): + return self._power_monitor.StopMonitoringPower() + + def ReadMsr(self, msr_number, start=0, length=64): + cmd = ['rdmsr', '-d', str(msr_number)] + (out, err) = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + if err: + raise OSError(err) + try: + result = int(out) + except ValueError: + raise OSError('Cannot interpret rdmsr output: %s' % out) + return result >> start & ((1 << length) - 1) + + def _IsIpfwKernelModuleInstalled(self): + return 'ipfw_mod' in subprocess.Popen( + ['lsmod'], stdout=subprocess.PIPE).communicate()[0] + + def _InstallIpfw(self): + ipfw_bin = binary_manager.FindPath( + 'ipfw', self.GetArchName(), self.GetOSName()) + ipfw_mod = binary_manager.FindPath( + 'ipfw_mod.ko', self.GetArchName(), self.GetOSName()) + + try: + changed = cloud_storage.GetIfChanged( + ipfw_bin, cloud_storage.INTERNAL_BUCKET) + changed |= cloud_storage.GetIfChanged( + ipfw_mod, cloud_storage.INTERNAL_BUCKET) + except cloud_storage.CloudStorageError, e: + logging.error(str(e)) + logging.error('You may proceed by manually building and installing' + 'dummynet for your kernel. See: ' + 'http://info.iet.unipi.it/~luigi/dummynet/') + sys.exit(1) + + if changed or not self.CanLaunchApplication('ipfw'): + if not self._IsIpfwKernelModuleInstalled(): + subprocess.check_call(['/usr/bin/sudo', 'insmod', ipfw_mod]) + os.chmod(ipfw_bin, 0755) + subprocess.check_call( + ['/usr/bin/sudo', 'cp', ipfw_bin, '/usr/local/sbin']) + + assert self.CanLaunchApplication('ipfw'), 'Failed to install ipfw. ' \ + 'ipfw provided binaries are not supported for linux kernel < 3.13. ' \ + 'You may proceed by manually building and installing dummynet for ' \ + 'your kernel. See: http://info.iet.unipi.it/~luigi/dummynet/' + + def _InstallBinary(self, bin_name): + bin_path = binary_manager.FetchPath( + bin_name, self.GetArchName(), self.GetOSName()) + os.environ['PATH'] += os.pathsep + os.path.dirname(bin_path) + assert self.CanLaunchApplication(bin_name), 'Failed to install ' + bin_name |