1
1
#!/usr/bin/env python
3
# $Id: __init__.py 531 2010-03-02 20:54:22Z billiejoex $
3
# $Id: __init__.py 954 2011-03-20 20:42:26Z g.rodola $
6
6
"""psutil is a module providing convenience functions for managing
7
7
processes in a portable way by using Python.
11
version_info = tuple([int(num) for num in __version__.split('.')])
15
"Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired",
17
"NUM_CPUS", "TOTAL_PHYMEM", "BOOT_TIME",
18
"version_info", "__version__",
19
"STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
20
"STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
21
"STATUS_WAKING", "STATUS_LOCKED",
25
"test", "pid_exists", "get_pid_list", "process_iter", "get_process_list",
26
"avail_phymem", "used_phymem", "total_virtmem", "avail_virtmem",
27
"used_virtmem", "cpu_times", "cpu_percent",
40
39
except ImportError:
43
# exceptions are imported here, but may be overriden by platform
44
# module implementation later
42
from psutil.error import Error, NoSuchProcess, AccessDenied, TimeoutExpired
43
from psutil._compat import property
44
from psutil._common import (STATUS_RUNNING, STATUS_IDLE, STATUS_SLEEPING,
45
STATUS_DISK_SLEEP, STATUS_STOPPED,
46
STATUS_TRACING_STOP, STATUS_ZOMBIE, STATUS_DEAD,
47
STATUS_WAKING, STATUS_LOCKED)
47
49
# import the appropriate module for our platform only
48
50
if sys.platform.lower().startswith("linux"):
49
from _pslinux import *
51
from psutil._pslinux import *
52
__all__.extend(["cached_phymem", "phymem_buffers"])
51
54
elif sys.platform.lower().startswith("win32"):
52
from _psmswindows import *
55
from psutil._psmswindows import *
56
__all__.extend(["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
57
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
58
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS"])
55
60
elif sys.platform.lower().startswith("darwin"):
61
from psutil._psosx import *
58
63
elif sys.platform.lower().startswith("freebsd"):
64
from psutil._psbsd import *
61
raise ImportError('no os specific module found')
63
# platform-specific modules define an Impl implementation class
64
_platform_impl = Impl()
68
"""This class contains information about CPU times.
69
It is not used directly but it's returned as an instance by
70
psutil.cpu_times() function.
72
Every CPU time is accessible in form of an attribute and represents
73
the time CPU has spent in the given mode.
75
The attributes availability varies depending on the platform.
76
Here follows a list of all available attributes:
83
- irq (Linux, FreeBSD)
87
def __init__(self, **kwargs):
90
setattr(self, name, kwargs[name])
91
self.__attrs.append(name)
95
for attr in self.__attrs:
96
value = getattr(self, attr)
97
string.append("%s=%s" %(attr, value))
98
return '; '.join(string)
101
for attr in self.__attrs:
102
yield getattr(self, attr)
105
class ProcessInfo(object):
106
"""Class that allows the process information to be passed between
107
external code and psutil. Used directly by the Process class.
110
def __init__(self, pid, ppid=None, name=None, path=None, cmdline=None,
116
self.cmdline = cmdline
117
# if we have the cmdline but not the path, figure it out from argv[0]
118
if cmdline and not path:
119
self.path = os.path.dirname(cmdline[0])
67
raise NotImplementedError('platform %s is not supported' % sys.platform)
126
70
class Process(object):
133
77
if not isinstance(pid, int):
134
78
raise ValueError("An integer is required")
135
79
if not pid_exists(pid):
136
raise NoSuchProcess("No process found with PID %s" % pid)
137
self._procinfo = ProcessInfo(pid)
139
# try to init CPU times, if it raises AccessDenied then suppress
140
# it so it won't interrupt the constructor. First call to
141
# get_cpu_percent() will trigger the AccessDenied exception
80
raise NoSuchProcess(pid, None, "no process found with PID %s" % pid)
82
# platform-specific modules define an PlatformProcess
83
# implementation class
84
self._platform_impl = PlatformProcess(pid)
85
self._last_sys_cpu_times = None
86
self._last_proc_cpu_times = None
144
self._last_sys_time = time.time()
145
self._last_user_time, self._last_kern_time = self.get_cpu_times()
91
name = repr(self.name)
92
cmdline = self.cmdline and repr(' '.join(self.cmdline))
94
details = "(pid=%s (terminated))" % self.pid
146
95
except AccessDenied:
147
self._last_user_time, self._last_kern_time = None, None
96
details = "(pid=%s)" % (self.pid)
99
details = "(pid=%s, name=%s, cmdline=%s)" % (pid, name, cmdline)
101
details = "(pid=%s, name=%s)" % (pid, name)
102
return "%s.%s%s" % (self.__class__.__module__,
103
self.__class__.__name__, details)
150
return "psutil.Process <PID:%s; PPID:%s; NAME:'%s'; PATH:'%s'; " \
151
"CMDLINE:%s; UID:%s; GID:%s;>" \
152
%(self.pid, self.ppid, self.name, self.path, self.cmdline, \
106
return "<%s at %s>" % (self.__str__(), id(self))
155
108
def __eq__(self, other):
156
"""Test for equality with another Process object based on PID
157
and creation time."""
158
# Avoid to use self.create_time directly to avoid caching in
159
# case kill() gets called before create_time resulting in
160
# NoSuchProcess not being raised (see issue 77):
161
h1 = (self.pid, self._procinfo.create or \
162
_platform_impl.get_process_create_time(self.pid))
163
h2 = (other.pid, other.create_time)
167
"""Used internally by Process properties. The first call to
168
deproxy() initializes the ProcessInfo object in self._procinfo
169
with process data read from platform-specific module's
170
get_process_info() method.
172
This method becomes a NO-OP after the first property is accessed.
173
Property data is filled in from the ProcessInfo object created,
174
and further calls to deproxy() simply return immediately without
175
calling get_process_info().
109
"""Test for equality with another Process object based on pid
178
# get_process_info returns a tuple we use as the arguments
179
# to the ProcessInfo constructor
180
self._procinfo = ProcessInfo(*_platform_impl.get_process_info(self._procinfo.pid))
181
self.is_proxy = False
112
h1 = (self.pid, self.create_time)
114
h2 = (other.pid, other.create_time)
115
except AttributeError:
185
122
"""The process pid."""
186
return self._procinfo.pid
190
127
"""The process parent pid."""
192
return self._procinfo.ppid
128
return self._platform_impl.get_process_ppid()
195
131
def parent(self):
196
"""Return the parent process as a Process object. If no ppid is
197
known then return None."""
198
if self.ppid is not None:
199
return Process(self.ppid)
132
"""Return the parent process as a Process object. If no parent
133
pid is known return None.
139
except NoSuchProcess:
204
144
"""The process name."""
206
return self._procinfo.name
145
name = self._platform_impl.get_process_name()
146
if os.name == 'posix':
147
# On UNIX the name gets truncated to the first 15 characters.
148
# If it matches the first part of the cmdline we return that
149
# one instead because it's usually more explicative.
150
# Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
151
cmdline = self.cmdline
153
extended_name = os.path.basename(cmdline[0])
154
if extended_name.startswith(name):
156
# XXX - perhaps needs refactoring
157
self._platform_impl._process_name = name
162
"""The process executable as an absolute path name."""
163
exe = self._platform_impl.get_process_exe()
164
# if we have the cmdline but not the exe, figure it out from argv[0]
166
cmdline = self.cmdline
167
if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
168
_exe = os.path.realpath(cmdline[0])
169
if os.path.isfile(_exe) and os.access(_exe, os.X_OK):
172
raise AccessDenied(self.pid, self._platform_impl._process_name)
210
"""The process path."""
212
return self._procinfo.path
177
msg = "'path' property is deprecated; use 'os.path.dirname(exe)' instead"
178
warnings.warn(msg, DeprecationWarning)
179
return os.path.dirname(self.exe)
215
182
def cmdline(self):
216
183
"""The command line process has been called with."""
218
return self._procinfo.cmdline
184
return self._platform_impl.get_process_cmdline()
188
"""The process current status as a STATUS_* constant."""
189
return self._platform_impl.get_process_status()
193
"""Get or set process niceness (priority)."""
194
return self._platform_impl.get_process_nice()
197
def nice(self, value):
198
# invoked on "p.nice = num"; change process niceness
199
return self._platform_impl.set_process_nice(value)
201
if os.name == 'posix':
205
"""Return a named tuple denoting the process real,
206
effective, and saved user ids.
208
return self._platform_impl.get_process_uids()
212
"""Return a named tuple denoting the process real,
213
effective, and saved group ids.
215
return self._platform_impl.get_process_gids()
222
"""The real user id of the current process."""
224
return self._procinfo.uid
219
"""The real user id of the current process (deprecated)."""
220
warnings.warn("'uid' property is deprecated; use 'uids.real' instead",
222
if os.name != 'posix':
224
return self.uids.real
228
"""The real group id of the current process."""
230
return self._procinfo.gid
228
"""The real group id of the current process (deprecated)."""
229
warnings.warn("'gid' property is deprecated; use 'uids.real' instead",
231
if os.name != 'posix':
233
return self.gids.real
233
236
def username(self):
234
"""The name of the user that owns the process."""
235
if self._procinfo.username is not None:
236
return self._procinfo.username
238
self._procinfo.username = pwd.getpwuid(self.uid).pw_name
237
"""The name of the user that owns the process.
238
On UNIX this is calculated by using *real* process uid.
240
if os.name == 'posix':
242
# might happen if python was installed from sources
243
raise ImportError("requires pwd module shipped with standard python")
244
return pwd.getpwuid(self.uids.real).pw_name
240
self._procinfo.username = _platform_impl.get_process_username(self.pid)
241
return self._procinfo.username
246
return self._platform_impl.get_process_username()
244
249
def create_time(self):
245
250
"""The process creation time as a floating point number
246
251
expressed in seconds since the epoch, in UTC.
248
if self._procinfo.create is None:
249
self._procinfo.create = _platform_impl.get_process_create_time(self.pid)
250
return self._procinfo.create
253
return self._platform_impl.get_process_create_time()
252
255
# available for Windows and Linux only
253
if hasattr(_platform_impl, "get_process_cwd"):
256
if hasattr(PlatformProcess, "get_process_cwd"):
254
258
def getcwd(self):
255
259
"""Return a string representing the process current working
258
return _platform_impl.get_process_cwd(self.pid)
261
"""Suspend process execution."""
262
# safety measure in case the current process has been killed in
263
# meantime and the kernel reused its PID
264
if not self.is_running():
267
if hasattr(_platform_impl, "suspend_process"):
268
_platform_impl.suspend_process(self.pid)
272
os.kill(self.pid, signal.SIGSTOP)
274
if err.errno == errno.ESRCH:
275
raise NoSuchProcess(self.pid)
279
"""Resume process execution."""
280
# safety measure in case the current process has been killed in
281
# meantime and the kernel reused its PID
282
if not self.is_running():
285
if hasattr(_platform_impl, "resume_process"):
286
_platform_impl.resume_process(self.pid)
290
os.kill(self.pid, signal.SIGCONT)
292
if err.errno == errno.ESRCH:
293
raise NoSuchProcess(self.pid)
296
def get_cpu_percent(self):
297
"""Compare process times to system time elapsed since last call
298
and calculate CPU utilization as a percentage. It is recommended
299
for accuracy that this function be called with at least 1 second
300
between calls. The initial delta is calculated from the
301
instantiation of the Process object.
304
# will raise AccessDenied on OS X if not root or in procmod group
305
user_t, kern_t = _platform_impl.get_cpu_times(self.pid)
307
total_proc_time = float((user_t - self._last_user_time) + \
308
(kern_t - self._last_kern_time))
262
return self._platform_impl.get_process_cwd()
264
# Linux, BSD and Windows only
265
if hasattr(PlatformProcess, "get_process_io_counters"):
267
def get_io_counters(self):
268
"""Return process I/O statistics as a namedtuple including
269
the number of read/write calls performed and the amount of
270
bytes read and written by the process.
272
return self._platform_impl.get_process_io_counters()
274
# available only on Linux
275
if hasattr(PlatformProcess, "get_process_ionice"):
277
def get_ionice(self):
278
"""Return process I/O niceness (priority) as a namedtuple."""
279
return self._platform_impl.get_process_ionice()
281
def set_ionice(self, ioclass, value=None):
282
"""Set process I/O niceness (priority).
283
ioclass is one of the IOPRIO_CLASS_* constants.
284
iodata is a number which goes from 0 to 7. The higher the
285
value, the lower the I/O priority of the process.
287
return self._platform_impl.set_process_ionice(ioclass, value)
289
def get_num_threads(self):
290
"""Return the number of threads used by this process."""
291
return self._platform_impl.get_process_num_threads()
293
def get_threads(self):
294
"""Return threads opened by process as a list of namedtuples
295
including thread id and thread CPU times (user/system).
297
return self._platform_impl.get_process_threads()
299
def get_children(self):
300
"""Return the children of this process as a list of Process
303
if not self.is_running():
304
name = self._platform_impl._process_name
305
raise NoSuchProcess(self.pid, name)
307
for proc in process_iter():
309
if proc.ppid == self.pid:
311
except NoSuchProcess:
315
def get_cpu_percent(self, interval=0.1):
316
"""Return a float representing the current process CPU
317
utilization as a percentage.
319
When interval is > 0.0 compares process times to system CPU
320
times elapsed before and after the interval (blocking).
322
When interval is 0.0 or None compares process times to system CPU
323
times elapsed since last call, returning immediately.
324
In this case is recommended for accuracy that this function be
325
called with at least 0.1 seconds between calls.
327
blocking = interval is not None and interval > 0.0
329
st1 = sum(cpu_times())
330
pt1 = self._platform_impl.get_cpu_times()
332
st2 = sum(cpu_times())
333
pt2 = self._platform_impl.get_cpu_times()
335
st1 = self._last_sys_cpu_times
336
pt1 = self._last_proc_cpu_times
337
st2 = sum(cpu_times())
338
pt2 = self._platform_impl.get_cpu_times()
339
if st1 is None or pt1 is None:
340
self._last_sys_cpu_times = st2
341
self._last_proc_cpu_times = pt2
344
delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
345
delta_time = st2 - st1
346
# reset values for next call in case of interval == None
347
self._last_sys_cpu_times = st2
348
self._last_proc_cpu_times = pt2
310
percent = total_proc_time / float((now - self._last_sys_time))
351
# the utilization split between all CPUs
352
overall_percent = (delta_proc / delta_time) * 100
311
353
except ZeroDivisionError:
315
self._last_sys_time = time.time()
316
self._last_user_time, self._last_kern_time = self.get_cpu_times()
318
return (percent * 100.0)
354
# interval was too low
356
# the utilization of a single CPU
357
single_cpu_percent = overall_percent * NUM_CPUS
358
# ugly hack to avoid troubles with float precision issues
359
if single_cpu_percent > 100.0:
361
return round(single_cpu_percent, 1)
320
363
def get_cpu_times(self):
321
364
"""Return a tuple whose values are process CPU user and system
322
time. These are the same first two values that os.times()
323
returns for the current process.
365
times. The same as os.times() but per-process.
325
return _platform_impl.get_cpu_times(self.pid)
367
return self._platform_impl.get_cpu_times()
327
369
def get_memory_info(self):
328
370
"""Return a tuple representing RSS (Resident Set Size) and VMS
333
375
On Windows RSS and VMS refer to "Mem Usage" and "VM Size" columns
336
return _platform_impl.get_memory_info(self.pid)
378
return self._platform_impl.get_memory_info()
338
380
def get_memory_percent(self):
339
381
"""Compare physical system memory to process resident memory and
340
382
calculate process memory utilization as a percentage.
342
rss = _platform_impl.get_memory_info(self.pid)[0]
384
rss = self._platform_impl.get_memory_info()[0]
344
386
return (rss / float(TOTAL_PHYMEM)) * 100
345
387
except ZeroDivisionError:
390
def get_open_files(self):
391
"""Return files opened by process as a list of namedtuples
392
including absolute file name and file descriptor number.
394
return self._platform_impl.get_open_files()
396
def get_connections(self):
397
"""Return TCP and UPD connections opened by process as a list
399
On BSD and OSX results for third party processes (!= os.getpid())
400
can differ depending on user privileges.
402
return self._platform_impl.get_connections()
348
404
def is_running(self):
349
"""Return whether the current process is running in the current process
405
"""Return whether the current process is running in the current
352
409
newproc = Process(self.pid)
353
410
return self == newproc
354
411
except NoSuchProcess:
357
def kill(self, sig=None):
358
"""Kill the current process by using signal sig (defaults to SIGKILL).
360
# safety measure in case the current process has been killed in
361
# meantime and the kernel reused its PID
362
if not self.is_running():
364
_platform_impl.kill_process(self.pid, sig)
368
"""Check whether the given PID exists in the current process list."""
369
return _platform_impl.pid_exists(pid)
372
"""Return a list of current running PIDs."""
373
return _platform_impl.get_pid_list()
414
def send_signal(self, sig):
415
"""Send a signal to process (see signal module constants).
416
On Windows only SIGTERM is valid and is treated as an alias
419
# safety measure in case the current process has been killed in
420
# meantime and the kernel reused its PID
421
if not self.is_running():
422
name = self._platform_impl._process_name
423
raise NoSuchProcess(self.pid, name)
424
if os.name == 'posix':
426
os.kill(self.pid, sig)
428
name = self._platform_impl._process_name
429
if err.errno == errno.ESRCH:
430
raise NoSuchProcess(self.pid, name)
431
if err.errno == errno.EPERM:
432
raise AccessDenied(self.pid, name)
435
if sig == signal.SIGTERM:
436
self._platform_impl.kill_process()
438
raise ValueError("only SIGTERM is supported on Windows")
441
"""Suspend process execution."""
442
# safety measure in case the current process has been killed in
443
# meantime and the kernel reused its PID
444
if not self.is_running():
445
name = self._platform_impl._process_name
446
raise NoSuchProcess(self.pid, name)
448
if hasattr(self._platform_impl, "suspend_process"):
449
self._platform_impl.suspend_process()
452
self.send_signal(signal.SIGSTOP)
455
"""Resume process execution."""
456
# safety measure in case the current process has been killed in
457
# meantime and the kernel reused its PID
458
if not self.is_running():
459
name = self._platform_impl._process_name
460
raise NoSuchProcess(self.pid, name)
462
if hasattr(self._platform_impl, "resume_process"):
463
self._platform_impl.resume_process()
466
self.send_signal(signal.SIGCONT)
469
"""Terminate the process with SIGTERM.
470
On Windows this is an alias for kill().
472
self.send_signal(signal.SIGTERM)
475
"""Kill the current process."""
476
# safety measure in case the current process has been killed in
477
# meantime and the kernel reused its PID
478
if not self.is_running():
479
name = self._platform_impl._process_name
480
raise NoSuchProcess(self.pid, name)
481
if os.name == 'posix':
482
self.send_signal(signal.SIGKILL)
484
self._platform_impl.kill_process()
486
def wait(self, timeout=None):
487
"""Wait for process to terminate and, if process is a children
488
of the current one also return its exit code, else None.
490
return self._platform_impl.process_wait(timeout)
493
class Popen(Process):
494
"""A more convenient interface to stdlib subprocess module.
495
It starts a sub process and deals with it exactly as when using
496
subprocess.Popen class but in addition also provides all the
497
property and methods of psutil.Process class in a unique interface:
500
>>> from subprocess import PIPE
501
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print 'hi'"], stdout=PIPE)
505
user(real=1000, effective=1000, saved=1000)
511
>>> p.wait(timeout=2)
515
For method names common to both classes such as kill(), terminate()
516
and wait(), psutil.Process implementation takes precedence.
518
For a complete documentation refers to:
519
http://docs.python.org/library/subprocess.html
522
def __init__(self, *args, **kwargs):
523
self.__subproc = subprocess.Popen(*args, **kwargs)
524
Process.__init__(self, self.__subproc.pid)
527
return list(set(dir(Popen) + dir(subprocess.Popen)))
529
def __getattribute__(self, name):
531
return object.__getattribute__(self, name)
532
except AttributeError:
534
return object.__getattribute__(self.__subproc, name)
535
except AttributeError:
536
raise AttributeError("%s instance has no attribute '%s'"
537
%(self.__class__.__name__, name))
375
540
def process_iter():
376
541
"""Return an iterator yielding a Process class instances for all
377
542
running processes on the local machine.
379
pids = _platform_impl.get_pid_list()
380
# for each PID, create a proxyied Process object
381
# it will lazy init it's name and path later if required
544
pids = get_pid_list()
384
547
yield Process(pid)