|
1 #!/usr/bin/env python |
|
2 |
|
3 # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. |
|
4 # Use of this source code is governed by a BSD-style license that can be |
|
5 # found in the LICENSE file. |
|
6 |
|
7 """OSX platform implementation.""" |
|
8 |
|
9 import errno |
|
10 import os |
|
11 import sys |
|
12 import warnings |
|
13 |
|
14 import _psutil_osx |
|
15 import _psutil_posix |
|
16 from psutil import _psposix |
|
17 from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired |
|
18 from psutil._compat import namedtuple, wraps |
|
19 from psutil._common import * |
|
20 |
|
21 __extra__all__ = [] |
|
22 |
|
23 # --- constants |
|
24 |
|
25 # Since these constants get determined at import time we do not want to |
|
26 # crash immediately; instead we'll set them to None and most likely |
|
27 # we'll crash later as they're used for determining process CPU stats |
|
28 # and creation_time |
|
29 try: |
|
30 NUM_CPUS = _psutil_osx.get_num_cpus() |
|
31 except Exception: |
|
32 NUM_CPUS = None |
|
33 warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) |
|
34 try: |
|
35 BOOT_TIME = _psutil_osx.get_system_boot_time() |
|
36 except Exception: |
|
37 BOOT_TIME = None |
|
38 warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) |
|
39 try: |
|
40 TOTAL_PHYMEM = _psutil_osx.get_virtual_mem()[0] |
|
41 except Exception: |
|
42 TOTAL_PHYMEM = None |
|
43 warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) |
|
44 |
|
45 _PAGESIZE = os.sysconf("SC_PAGE_SIZE") |
|
46 _cputimes_ntuple = namedtuple('cputimes', 'user nice system idle') |
|
47 # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h |
|
48 _TCP_STATES_TABLE = {_psutil_osx.TCPS_ESTABLISHED : CONN_ESTABLISHED, |
|
49 _psutil_osx.TCPS_SYN_SENT : CONN_SYN_SENT, |
|
50 _psutil_osx.TCPS_SYN_RECEIVED : CONN_SYN_RECV, |
|
51 _psutil_osx.TCPS_FIN_WAIT_1 : CONN_FIN_WAIT1, |
|
52 _psutil_osx.TCPS_FIN_WAIT_2 : CONN_FIN_WAIT2, |
|
53 _psutil_osx.TCPS_TIME_WAIT : CONN_TIME_WAIT, |
|
54 _psutil_osx.TCPS_CLOSED : CONN_CLOSE, |
|
55 _psutil_osx.TCPS_CLOSE_WAIT : CONN_CLOSE_WAIT, |
|
56 _psutil_osx.TCPS_LAST_ACK : CONN_LAST_ACK, |
|
57 _psutil_osx.TCPS_LISTEN : CONN_LISTEN, |
|
58 _psutil_osx.TCPS_CLOSING : CONN_CLOSING, |
|
59 _psutil_osx.PSUTIL_CONN_NONE : CONN_NONE, |
|
60 } |
|
61 |
|
62 # --- functions |
|
63 |
|
64 get_system_boot_time = _psutil_osx.get_system_boot_time |
|
65 |
|
66 nt_virtmem_info = namedtuple('vmem', ' '.join([ |
|
67 # all platforms |
|
68 'total', 'available', 'percent', 'used', 'free', |
|
69 # OSX specific |
|
70 'active', |
|
71 'inactive', |
|
72 'wired'])) |
|
73 |
|
74 def virtual_memory(): |
|
75 """System virtual memory as a namedtuple.""" |
|
76 total, active, inactive, wired, free = _psutil_osx.get_virtual_mem() |
|
77 avail = inactive + free |
|
78 used = active + inactive + wired |
|
79 percent = usage_percent((total - avail), total, _round=1) |
|
80 return nt_virtmem_info(total, avail, percent, used, free, |
|
81 active, inactive, wired) |
|
82 |
|
83 def swap_memory(): |
|
84 """Swap system memory as a (total, used, free, sin, sout) tuple.""" |
|
85 total, used, free, sin, sout = _psutil_osx.get_swap_mem() |
|
86 percent = usage_percent(used, total, _round=1) |
|
87 return nt_swapmeminfo(total, used, free, percent, sin, sout) |
|
88 |
|
89 def get_system_cpu_times(): |
|
90 """Return system CPU times as a namedtuple.""" |
|
91 user, nice, system, idle = _psutil_osx.get_system_cpu_times() |
|
92 return _cputimes_ntuple(user, nice, system, idle) |
|
93 |
|
94 def get_system_per_cpu_times(): |
|
95 """Return system CPU times as a named tuple""" |
|
96 ret = [] |
|
97 for cpu_t in _psutil_osx.get_system_per_cpu_times(): |
|
98 user, nice, system, idle = cpu_t |
|
99 item = _cputimes_ntuple(user, nice, system, idle) |
|
100 ret.append(item) |
|
101 return ret |
|
102 |
|
103 def disk_partitions(all=False): |
|
104 retlist = [] |
|
105 partitions = _psutil_osx.get_disk_partitions() |
|
106 for partition in partitions: |
|
107 device, mountpoint, fstype, opts = partition |
|
108 if device == 'none': |
|
109 device = '' |
|
110 if not all: |
|
111 if not os.path.isabs(device) \ |
|
112 or not os.path.exists(device): |
|
113 continue |
|
114 ntuple = nt_partition(device, mountpoint, fstype, opts) |
|
115 retlist.append(ntuple) |
|
116 return retlist |
|
117 |
|
118 def get_system_users(): |
|
119 retlist = [] |
|
120 rawlist = _psutil_osx.get_system_users() |
|
121 for item in rawlist: |
|
122 user, tty, hostname, tstamp = item |
|
123 if tty == '~': |
|
124 continue # reboot or shutdown |
|
125 if not tstamp: |
|
126 continue |
|
127 nt = nt_user(user, tty or None, hostname or None, tstamp) |
|
128 retlist.append(nt) |
|
129 return retlist |
|
130 |
|
131 |
|
132 get_pid_list = _psutil_osx.get_pid_list |
|
133 pid_exists = _psposix.pid_exists |
|
134 get_disk_usage = _psposix.get_disk_usage |
|
135 net_io_counters = _psutil_osx.get_net_io_counters |
|
136 disk_io_counters = _psutil_osx.get_disk_io_counters |
|
137 |
|
138 # --- decorator |
|
139 |
|
140 def wrap_exceptions(fun): |
|
141 """Decorator which translates bare OSError exceptions into |
|
142 NoSuchProcess and AccessDenied. |
|
143 """ |
|
144 @wraps(fun) |
|
145 def wrapper(self, *args, **kwargs): |
|
146 try: |
|
147 return fun(self, *args, **kwargs) |
|
148 except OSError: |
|
149 err = sys.exc_info()[1] |
|
150 if err.errno == errno.ESRCH: |
|
151 raise NoSuchProcess(self.pid, self._process_name) |
|
152 if err.errno in (errno.EPERM, errno.EACCES): |
|
153 raise AccessDenied(self.pid, self._process_name) |
|
154 raise |
|
155 return wrapper |
|
156 |
|
157 |
|
158 _status_map = { |
|
159 _psutil_osx.SIDL : STATUS_IDLE, |
|
160 _psutil_osx.SRUN : STATUS_RUNNING, |
|
161 _psutil_osx.SSLEEP : STATUS_SLEEPING, |
|
162 _psutil_osx.SSTOP : STATUS_STOPPED, |
|
163 _psutil_osx.SZOMB : STATUS_ZOMBIE, |
|
164 } |
|
165 |
|
166 class Process(object): |
|
167 """Wrapper class around underlying C implementation.""" |
|
168 |
|
169 __slots__ = ["pid", "_process_name"] |
|
170 |
|
171 def __init__(self, pid): |
|
172 self.pid = pid |
|
173 self._process_name = None |
|
174 |
|
175 @wrap_exceptions |
|
176 def get_process_name(self): |
|
177 """Return process name as a string of limited len (15).""" |
|
178 return _psutil_osx.get_process_name(self.pid) |
|
179 |
|
180 @wrap_exceptions |
|
181 def get_process_exe(self): |
|
182 return _psutil_osx.get_process_exe(self.pid) |
|
183 |
|
184 @wrap_exceptions |
|
185 def get_process_cmdline(self): |
|
186 """Return process cmdline as a list of arguments.""" |
|
187 if not pid_exists(self.pid): |
|
188 raise NoSuchProcess(self.pid, self._process_name) |
|
189 return _psutil_osx.get_process_cmdline(self.pid) |
|
190 |
|
191 @wrap_exceptions |
|
192 def get_process_ppid(self): |
|
193 """Return process parent pid.""" |
|
194 return _psutil_osx.get_process_ppid(self.pid) |
|
195 |
|
196 @wrap_exceptions |
|
197 def get_process_cwd(self): |
|
198 return _psutil_osx.get_process_cwd(self.pid) |
|
199 |
|
200 @wrap_exceptions |
|
201 def get_process_uids(self): |
|
202 real, effective, saved = _psutil_osx.get_process_uids(self.pid) |
|
203 return nt_uids(real, effective, saved) |
|
204 |
|
205 @wrap_exceptions |
|
206 def get_process_gids(self): |
|
207 real, effective, saved = _psutil_osx.get_process_gids(self.pid) |
|
208 return nt_gids(real, effective, saved) |
|
209 |
|
210 @wrap_exceptions |
|
211 def get_process_terminal(self): |
|
212 tty_nr = _psutil_osx.get_process_tty_nr(self.pid) |
|
213 tmap = _psposix._get_terminal_map() |
|
214 try: |
|
215 return tmap[tty_nr] |
|
216 except KeyError: |
|
217 return None |
|
218 |
|
219 @wrap_exceptions |
|
220 def get_memory_info(self): |
|
221 """Return a tuple with the process' RSS and VMS size.""" |
|
222 rss, vms = _psutil_osx.get_process_memory_info(self.pid)[:2] |
|
223 return nt_meminfo(rss, vms) |
|
224 |
|
225 _nt_ext_mem = namedtuple('meminfo', 'rss vms pfaults pageins') |
|
226 |
|
227 @wrap_exceptions |
|
228 def get_ext_memory_info(self): |
|
229 """Return a tuple with the process' RSS and VMS size.""" |
|
230 rss, vms, pfaults, pageins = _psutil_osx.get_process_memory_info(self.pid) |
|
231 return self._nt_ext_mem(rss, vms, |
|
232 pfaults * _PAGESIZE, |
|
233 pageins * _PAGESIZE) |
|
234 |
|
235 @wrap_exceptions |
|
236 def get_cpu_times(self): |
|
237 user, system = _psutil_osx.get_process_cpu_times(self.pid) |
|
238 return nt_cputimes(user, system) |
|
239 |
|
240 @wrap_exceptions |
|
241 def get_process_create_time(self): |
|
242 """Return the start time of the process as a number of seconds since |
|
243 the epoch.""" |
|
244 return _psutil_osx.get_process_create_time(self.pid) |
|
245 |
|
246 @wrap_exceptions |
|
247 def get_num_ctx_switches(self): |
|
248 return nt_ctxsw(*_psutil_osx.get_process_num_ctx_switches(self.pid)) |
|
249 |
|
250 @wrap_exceptions |
|
251 def get_process_num_threads(self): |
|
252 """Return the number of threads belonging to the process.""" |
|
253 return _psutil_osx.get_process_num_threads(self.pid) |
|
254 |
|
255 @wrap_exceptions |
|
256 def get_open_files(self): |
|
257 """Return files opened by process.""" |
|
258 if self.pid == 0: |
|
259 return [] |
|
260 files = [] |
|
261 rawlist = _psutil_osx.get_process_open_files(self.pid) |
|
262 for path, fd in rawlist: |
|
263 if isfile_strict(path): |
|
264 ntuple = nt_openfile(path, fd) |
|
265 files.append(ntuple) |
|
266 return files |
|
267 |
|
268 @wrap_exceptions |
|
269 def get_connections(self, kind='inet'): |
|
270 """Return etwork connections opened by a process as a list of |
|
271 namedtuples. |
|
272 """ |
|
273 if kind not in conn_tmap: |
|
274 raise ValueError("invalid %r kind argument; choose between %s" |
|
275 % (kind, ', '.join([repr(x) for x in conn_tmap]))) |
|
276 families, types = conn_tmap[kind] |
|
277 rawlist = _psutil_osx.get_process_connections(self.pid, families, types) |
|
278 ret = [] |
|
279 for item in rawlist: |
|
280 fd, fam, type, laddr, raddr, status = item |
|
281 status = _TCP_STATES_TABLE[status] |
|
282 nt = nt_connection(fd, fam, type, laddr, raddr, status) |
|
283 ret.append(nt) |
|
284 return ret |
|
285 |
|
286 @wrap_exceptions |
|
287 def get_num_fds(self): |
|
288 if self.pid == 0: |
|
289 return 0 |
|
290 return _psutil_osx.get_process_num_fds(self.pid) |
|
291 |
|
292 @wrap_exceptions |
|
293 def process_wait(self, timeout=None): |
|
294 try: |
|
295 return _psposix.wait_pid(self.pid, timeout) |
|
296 except TimeoutExpired: |
|
297 raise TimeoutExpired(self.pid, self._process_name) |
|
298 |
|
299 @wrap_exceptions |
|
300 def get_process_nice(self): |
|
301 return _psutil_posix.getpriority(self.pid) |
|
302 |
|
303 @wrap_exceptions |
|
304 def set_process_nice(self, value): |
|
305 return _psutil_posix.setpriority(self.pid, value) |
|
306 |
|
307 @wrap_exceptions |
|
308 def get_process_status(self): |
|
309 code = _psutil_osx.get_process_status(self.pid) |
|
310 if code in _status_map: |
|
311 return _status_map[code] |
|
312 return constant(-1, "?") |
|
313 |
|
314 @wrap_exceptions |
|
315 def get_process_threads(self): |
|
316 """Return the number of threads belonging to the process.""" |
|
317 rawlist = _psutil_osx.get_process_threads(self.pid) |
|
318 retlist = [] |
|
319 for thread_id, utime, stime in rawlist: |
|
320 ntuple = nt_thread(thread_id, utime, stime) |
|
321 retlist.append(ntuple) |
|
322 return retlist |
|
323 |
|
324 nt_mmap_grouped = namedtuple('mmap', |
|
325 'path rss private swapped dirtied ref_count shadow_depth') |
|
326 nt_mmap_ext = namedtuple('mmap', |
|
327 'addr perms path rss private swapped dirtied ref_count shadow_depth') |
|
328 |
|
329 @wrap_exceptions |
|
330 def get_memory_maps(self): |
|
331 return _psutil_osx.get_process_memory_maps(self.pid) |