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.
9 import resource # pylint: disable=F0401
11 resource = None # Not available on all platforms
13 from telemetry import decorators
14 from telemetry.core.platform import platform_backend
15 from telemetry.core.platform import posix_platform_backend
16 from telemetry.core.platform.power_monitor import powermetrics_power_monitor
19 class MacPlatformBackend(posix_platform_backend.PosixPlatformBackend):
21 super(MacPlatformBackend, self).__init__()
23 self.power_monitor_ = powermetrics_power_monitor.PowerMetricsPowerMonitor(
26 def StartRawDisplayFrameRateMeasurement(self):
27 raise NotImplementedError()
29 def StopRawDisplayFrameRateMeasurement(self):
30 raise NotImplementedError()
32 def GetRawDisplayFrameRateMeasurements(self):
33 raise NotImplementedError()
35 def IsThermallyThrottled(self):
36 raise NotImplementedError()
38 def HasBeenThermallyThrottled(self):
39 raise NotImplementedError()
41 def _GetIdleWakeupCount(self, pid):
42 top_output = self._GetTopOutput(pid, ['idlew'])
44 # Sometimes top won't return anything here, just ignore such cases -
46 if top_output[-2] != 'IDLEW':
48 # Numbers reported by top may have a '+' appended.
49 wakeup_count = int(top_output[-1].strip('+ '))
52 def GetCpuStats(self, pid):
53 """Return current cpu processing time of pid in seconds."""
54 class ProcTaskInfo(ctypes.Structure):
55 """Struct for proc_pidinfo() call."""
56 _fields_ = [("pti_virtual_size", ctypes.c_uint64),
57 ("pti_resident_size", ctypes.c_uint64),
58 ("pti_total_user", ctypes.c_uint64),
59 ("pti_total_system", ctypes.c_uint64),
60 ("pti_threads_user", ctypes.c_uint64),
61 ("pti_threads_system", ctypes.c_uint64),
62 ("pti_policy", ctypes.c_int32),
63 ("pti_faults", ctypes.c_int32),
64 ("pti_pageins", ctypes.c_int32),
65 ("pti_cow_faults", ctypes.c_int32),
66 ("pti_messages_sent", ctypes.c_int32),
67 ("pti_messages_received", ctypes.c_int32),
68 ("pti_syscalls_mach", ctypes.c_int32),
69 ("pti_syscalls_unix", ctypes.c_int32),
70 ("pti_csw", ctypes.c_int32),
71 ("pti_threadnum", ctypes.c_int32),
72 ("pti_numrunning", ctypes.c_int32),
73 ("pti_priority", ctypes.c_int32)]
76 self.size = ctypes.sizeof(self)
77 super(ProcTaskInfo, self).__init__()
79 proc_info = ProcTaskInfo()
81 self.libproc = ctypes.CDLL(ctypes.util.find_library('libproc'))
82 self.libproc.proc_pidinfo(pid, proc_info.PROC_PIDTASKINFO, 0,
83 ctypes.byref(proc_info), proc_info.size)
85 # Convert nanoseconds to seconds.
86 cpu_time = (proc_info.pti_total_user / 1000000000.0 +
87 proc_info.pti_total_system / 1000000000.0)
88 results = {'CpuProcessTime': cpu_time,
89 'ContextSwitches': proc_info.pti_csw}
91 # top only reports idle wakeup count starting from OS X 10.9.
92 if self.GetOSVersionName() >= platform_backend.MAVERICKS:
93 results.update({'IdleWakeupCount': self._GetIdleWakeupCount(pid)})
96 def GetCpuTimestamp(self):
97 """Return current timestamp in seconds."""
98 return {'TotalTime': time.time()}
100 def GetSystemCommitCharge(self):
101 vm_stat = self._RunCommand(['vm_stat'])
102 for stat in vm_stat.splitlines():
103 key, value = stat.split(':')
104 if key == 'Pages active':
105 pages_active = int(value.strip()[:-1]) # Strip trailing '.'
106 return pages_active * resource.getpagesize() / 1024
110 def GetSystemTotalPhysicalMemory(self):
111 return int(self._RunCommand(['sysctl', '-n', 'hw.memsize']))
113 def PurgeUnpinnedMemory(self):
114 # TODO(pliard): Implement this.
117 def GetMemoryStats(self, pid):
118 rss_vsz = self._GetPsOutput(['rss', 'vsz'], pid)
120 rss, vsz = rss_vsz[0].split()
121 return {'VM': 1024 * int(vsz),
122 'WorkingSetSize': 1024 * int(rss)}
129 def GetOSVersionName(self):
130 os_version = os.uname()[2]
132 if os_version.startswith('9.'):
133 return platform_backend.LEOPARD
134 if os_version.startswith('10.'):
135 return platform_backend.SNOWLEOPARD
136 if os_version.startswith('11.'):
137 return platform_backend.LION
138 if os_version.startswith('12.'):
139 return platform_backend.MOUNTAINLION
140 if os_version.startswith('13.'):
141 return platform_backend.MAVERICKS
143 raise NotImplementedError('Unknown mac version %s.' % os_version)
145 def CanFlushIndividualFilesFromSystemCache(self):
148 def FlushEntireSystemCache(self):
149 mavericks_or_later = self.GetOSVersionName() >= platform_backend.MAVERICKS
150 p = self.LaunchApplication('purge', elevate_privilege=mavericks_or_later)
152 assert p.returncode == 0, 'Failed to flush system cache'
154 def CanMonitorPower(self):
155 return self.power_monitor_.CanMonitorPower()
157 def StartMonitoringPower(self, browser):
158 self.power_monitor_.StartMonitoringPower(browser)
160 def StopMonitoringPower(self):
161 return self.power_monitor_.StopMonitoringPower()