diff options
Diffstat (limited to 'catapult/telemetry/telemetry/internal/platform/mac_platform_backend.py')
-rw-r--r-- | catapult/telemetry/telemetry/internal/platform/mac_platform_backend.py | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/catapult/telemetry/telemetry/internal/platform/mac_platform_backend.py b/catapult/telemetry/telemetry/internal/platform/mac_platform_backend.py new file mode 100644 index 00000000..c271825b --- /dev/null +++ b/catapult/telemetry/telemetry/internal/platform/mac_platform_backend.py @@ -0,0 +1,194 @@ +# 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 ctypes +import os +import platform +import subprocess +import sys +import time + +from telemetry.core import os_version as os_version_module +from telemetry import decorators +from telemetry.internal.platform import posix_platform_backend +from telemetry.internal.platform.power_monitor import powermetrics_power_monitor +from telemetry.util import process_statistic_timeline_data + +try: + import resource # pylint: disable=import-error +except ImportError: + resource = None # Not available on all platforms + + + +class MacPlatformBackend(posix_platform_backend.PosixPlatformBackend): + def __init__(self): + super(MacPlatformBackend, self).__init__() + self.libproc = None + self._power_monitor = powermetrics_power_monitor.PowerMetricsPowerMonitor( + self) + + def GetSystemLog(self): + # Since the log file can be very large, only show the last 1000 lines. + return subprocess.check_output( + ['tail', '-n', '1000', '/var/log/system.log']) + + @classmethod + def IsPlatformBackendForHost(cls): + return sys.platform == 'darwin' + + def IsThermallyThrottled(self): + raise NotImplementedError() + + def HasBeenThermallyThrottled(self): + raise NotImplementedError() + + def _GetIdleWakeupCount(self, pid): + top_output = self._GetTopOutput(pid, ['idlew']) + + # Sometimes top won't return anything here, just ignore such cases - + # crbug.com/354812 . + if top_output[-2] != 'IDLEW': + return process_statistic_timeline_data.IdleWakeupTimelineData(pid, 0) + # Numbers reported by top may have a '+' appended. + wakeup_count = int(top_output[-1].strip('+ ')) + return process_statistic_timeline_data.IdleWakeupTimelineData(pid, + wakeup_count) + + def GetCpuStats(self, pid): + """Returns a dict of cpu statistics for the process represented by |pid|.""" + class ProcTaskInfo(ctypes.Structure): + """Struct for proc_pidinfo() call.""" + _fields_ = [("pti_virtual_size", ctypes.c_uint64), + ("pti_resident_size", ctypes.c_uint64), + ("pti_total_user", ctypes.c_uint64), + ("pti_total_system", ctypes.c_uint64), + ("pti_threads_user", ctypes.c_uint64), + ("pti_threads_system", ctypes.c_uint64), + ("pti_policy", ctypes.c_int32), + ("pti_faults", ctypes.c_int32), + ("pti_pageins", ctypes.c_int32), + ("pti_cow_faults", ctypes.c_int32), + ("pti_messages_sent", ctypes.c_int32), + ("pti_messages_received", ctypes.c_int32), + ("pti_syscalls_mach", ctypes.c_int32), + ("pti_syscalls_unix", ctypes.c_int32), + ("pti_csw", ctypes.c_int32), + ("pti_threadnum", ctypes.c_int32), + ("pti_numrunning", ctypes.c_int32), + ("pti_priority", ctypes.c_int32)] + PROC_PIDTASKINFO = 4 + def __init__(self): + self.size = ctypes.sizeof(self) + super(ProcTaskInfo, self).__init__() # pylint: disable=bad-super-call + + proc_info = ProcTaskInfo() + if not self.libproc: + self.libproc = ctypes.CDLL(ctypes.util.find_library('libproc')) + self.libproc.proc_pidinfo(pid, proc_info.PROC_PIDTASKINFO, 0, + ctypes.byref(proc_info), proc_info.size) + + # Convert nanoseconds to seconds. + cpu_time = (proc_info.pti_total_user / 1000000000.0 + + proc_info.pti_total_system / 1000000000.0) + results = {'CpuProcessTime': cpu_time, + 'ContextSwitches': proc_info.pti_csw} + + # top only reports idle wakeup count starting from OS X 10.9. + if self.GetOSVersionName() >= os_version_module.MAVERICKS: + results.update({'IdleWakeupCount': self._GetIdleWakeupCount(pid)}) + return results + + def GetCpuTimestamp(self): + """Return current timestamp in seconds.""" + return {'TotalTime': time.time()} + + def GetSystemCommitCharge(self): + vm_stat = self.RunCommand(['vm_stat']) + for stat in vm_stat.splitlines(): + key, value = stat.split(':') + if key == 'Pages active': + pages_active = int(value.strip()[:-1]) # Strip trailing '.' + return pages_active * resource.getpagesize() / 1024 + return 0 + + @decorators.Cache + def GetSystemTotalPhysicalMemory(self): + return int(self.RunCommand(['sysctl', '-n', 'hw.memsize'])) + + def PurgeUnpinnedMemory(self): + # TODO(pliard): Implement this. + pass + + @decorators.Deprecated( + 2017, 11, 4, + 'Clients should use tracing and memory-infra in new Telemetry ' + 'benchmarks. See for context: https://crbug.com/632021') + def GetMemoryStats(self, pid): + rss_vsz = self.GetPsOutput(['rss', 'vsz'], pid) + if rss_vsz: + rss, vsz = rss_vsz[0].split() + return {'VM': 1024 * int(vsz), + 'WorkingSetSize': 1024 * int(rss)} + return {} + + @decorators.Cache + def GetArchName(self): + return platform.machine() + + def GetOSName(self): + return 'mac' + + @decorators.Cache + def GetOSVersionName(self): + os_version = os.uname()[2] + + if os_version.startswith('9.'): + return os_version_module.LEOPARD + if os_version.startswith('10.'): + return os_version_module.SNOWLEOPARD + if os_version.startswith('11.'): + return os_version_module.LION + if os_version.startswith('12.'): + return os_version_module.MOUNTAINLION + if os_version.startswith('13.'): + return os_version_module.MAVERICKS + if os_version.startswith('14.'): + return os_version_module.YOSEMITE + if os_version.startswith('15.'): + return os_version_module.ELCAPITAN + if os_version.startswith('16.'): + return os_version_module.SIERRA + + raise NotImplementedError('Unknown mac version %s.' % os_version) + + def CanTakeScreenshot(self): + return True + + def TakeScreenshot(self, file_path): + return subprocess.call(['screencapture', file_path]) + + def CanFlushIndividualFilesFromSystemCache(self): + return False + + def SupportFlushEntireSystemCache(self): + return self.HasRootAccess() + + def FlushEntireSystemCache(self): + mavericks_or_later = self.GetOSVersionName() >= os_version_module.MAVERICKS + p = self.LaunchApplication('purge', elevate_privilege=mavericks_or_later) + p.communicate() + assert p.returncode == 0, 'Failed to flush system cache' + + 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() |