aboutsummaryrefslogtreecommitdiff
path: root/catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py')
-rw-r--r--catapult/telemetry/telemetry/internal/platform/linux_platform_backend.py162
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