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.
10 from telemetry import decorators
11 from telemetry.core.platform import platform_backend
12 from telemetry.core.platform import posix_platform_backend
13 from telemetry.core.platform import process_statistic_timeline_data
14 from telemetry.core.platform.power_monitor import powermetrics_power_monitor
17 import resource # pylint: disable=F0401
19 resource = None # Not available on all platforms
23 class MacPlatformBackend(posix_platform_backend.PosixPlatformBackend):
25 super(MacPlatformBackend, self).__init__()
27 self._power_monitor = powermetrics_power_monitor.PowerMetricsPowerMonitor(
30 def StartRawDisplayFrameRateMeasurement(self):
31 raise NotImplementedError()
33 def StopRawDisplayFrameRateMeasurement(self):
34 raise NotImplementedError()
36 def GetRawDisplayFrameRateMeasurements(self):
37 raise NotImplementedError()
39 def IsThermallyThrottled(self):
40 raise NotImplementedError()
42 def HasBeenThermallyThrottled(self):
43 raise NotImplementedError()
45 def _GetIdleWakeupCount(self, pid):
46 top_output = self._GetTopOutput(pid, ['idlew'])
48 # Sometimes top won't return anything here, just ignore such cases -
50 if top_output[-2] != 'IDLEW':
51 return process_statistic_timeline_data.IdleWakeupTimelineData(pid, 0)
52 # Numbers reported by top may have a '+' appended.
53 wakeup_count = int(top_output[-1].strip('+ '))
54 return process_statistic_timeline_data.IdleWakeupTimelineData(pid,
57 def GetCpuStats(self, pid):
58 """Returns a dict of cpu statistics for the process represented by |pid|."""
59 class ProcTaskInfo(ctypes.Structure):
60 """Struct for proc_pidinfo() call."""
61 _fields_ = [("pti_virtual_size", ctypes.c_uint64),
62 ("pti_resident_size", ctypes.c_uint64),
63 ("pti_total_user", ctypes.c_uint64),
64 ("pti_total_system", ctypes.c_uint64),
65 ("pti_threads_user", ctypes.c_uint64),
66 ("pti_threads_system", ctypes.c_uint64),
67 ("pti_policy", ctypes.c_int32),
68 ("pti_faults", ctypes.c_int32),
69 ("pti_pageins", ctypes.c_int32),
70 ("pti_cow_faults", ctypes.c_int32),
71 ("pti_messages_sent", ctypes.c_int32),
72 ("pti_messages_received", ctypes.c_int32),
73 ("pti_syscalls_mach", ctypes.c_int32),
74 ("pti_syscalls_unix", ctypes.c_int32),
75 ("pti_csw", ctypes.c_int32),
76 ("pti_threadnum", ctypes.c_int32),
77 ("pti_numrunning", ctypes.c_int32),
78 ("pti_priority", ctypes.c_int32)]
81 self.size = ctypes.sizeof(self)
82 super(ProcTaskInfo, self).__init__()
84 proc_info = ProcTaskInfo()
86 self.libproc = ctypes.CDLL(ctypes.util.find_library('libproc'))
87 self.libproc.proc_pidinfo(pid, proc_info.PROC_PIDTASKINFO, 0,
88 ctypes.byref(proc_info), proc_info.size)
90 # Convert nanoseconds to seconds.
91 cpu_time = (proc_info.pti_total_user / 1000000000.0 +
92 proc_info.pti_total_system / 1000000000.0)
93 results = {'CpuProcessTime': cpu_time,
94 'ContextSwitches': proc_info.pti_csw}
96 # top only reports idle wakeup count starting from OS X 10.9.
97 if self.GetOSVersionName() >= platform_backend.MAVERICKS:
98 results.update({'IdleWakeupCount': self._GetIdleWakeupCount(pid)})
101 def GetCpuTimestamp(self):
102 """Return current timestamp in seconds."""
103 return {'TotalTime': time.time()}
105 def GetSystemCommitCharge(self):
106 vm_stat = self.RunCommand(['vm_stat'])
107 for stat in vm_stat.splitlines():
108 key, value = stat.split(':')
109 if key == 'Pages active':
110 pages_active = int(value.strip()[:-1]) # Strip trailing '.'
111 return pages_active * resource.getpagesize() / 1024
115 def GetSystemTotalPhysicalMemory(self):
116 return int(self.RunCommand(['sysctl', '-n', 'hw.memsize']))
118 def PurgeUnpinnedMemory(self):
119 # TODO(pliard): Implement this.
122 def GetMemoryStats(self, pid):
123 rss_vsz = self.GetPsOutput(['rss', 'vsz'], pid)
125 rss, vsz = rss_vsz[0].split()
126 return {'VM': 1024 * int(vsz),
127 'WorkingSetSize': 1024 * int(rss)}
131 def GetArchName(self):
132 return platform.machine()
138 def GetOSVersionName(self):
139 os_version = os.uname()[2]
141 if os_version.startswith('9.'):
142 return platform_backend.LEOPARD
143 if os_version.startswith('10.'):
144 return platform_backend.SNOWLEOPARD
145 if os_version.startswith('11.'):
146 return platform_backend.LION
147 if os_version.startswith('12.'):
148 return platform_backend.MOUNTAINLION
149 if os_version.startswith('13.'):
150 return platform_backend.MAVERICKS
151 if os_version.startswith('14.'):
152 return platform_backend.YOSEMITE
154 raise NotImplementedError('Unknown mac version %s.' % os_version)
156 def CanFlushIndividualFilesFromSystemCache(self):
159 def FlushEntireSystemCache(self):
160 mavericks_or_later = self.GetOSVersionName() >= platform_backend.MAVERICKS
161 p = self.LaunchApplication('purge', elevate_privilege=mavericks_or_later)
163 assert p.returncode == 0, 'Failed to flush system cache'
165 def CanMonitorPower(self):
166 return self._power_monitor.CanMonitorPower()
168 def CanMeasurePerApplicationPower(self):
169 return self._power_monitor.CanMeasurePerApplicationPower()
171 def StartMonitoringPower(self, browser):
172 self._power_monitor.StartMonitoringPower(browser)
174 def StopMonitoringPower(self):
175 return self._power_monitor.StopMonitoringPower()