Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/psutil/__init__.py: 26%
943 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1# -*- coding: utf-8 -*-
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.
7"""psutil is a cross-platform library for retrieving information on
8running processes and system utilization (CPU, memory, disks, network,
9sensors) in Python. Supported platforms:
11 - Linux
12 - Windows
13 - macOS
14 - FreeBSD
15 - OpenBSD
16 - NetBSD
17 - Sun Solaris
18 - AIX
20Works with Python versions 2.7 and 3.4+.
21"""
23from __future__ import division
25import collections
26import contextlib
27import datetime
28import functools
29import os
30import signal
31import subprocess
32import sys
33import threading
34import time
37try:
38 import pwd
39except ImportError:
40 pwd = None
42from . import _common
43from ._common import AIX
44from ._common import BSD
45from ._common import CONN_CLOSE
46from ._common import CONN_CLOSE_WAIT
47from ._common import CONN_CLOSING
48from ._common import CONN_ESTABLISHED
49from ._common import CONN_FIN_WAIT1
50from ._common import CONN_FIN_WAIT2
51from ._common import CONN_LAST_ACK
52from ._common import CONN_LISTEN
53from ._common import CONN_NONE
54from ._common import CONN_SYN_RECV
55from ._common import CONN_SYN_SENT
56from ._common import CONN_TIME_WAIT
57from ._common import FREEBSD # NOQA
58from ._common import LINUX
59from ._common import MACOS
60from ._common import NETBSD # NOQA
61from ._common import NIC_DUPLEX_FULL
62from ._common import NIC_DUPLEX_HALF
63from ._common import NIC_DUPLEX_UNKNOWN
64from ._common import OPENBSD # NOQA
65from ._common import OSX # deprecated alias
66from ._common import POSIX # NOQA
67from ._common import POWER_TIME_UNKNOWN
68from ._common import POWER_TIME_UNLIMITED
69from ._common import STATUS_DEAD
70from ._common import STATUS_DISK_SLEEP
71from ._common import STATUS_IDLE
72from ._common import STATUS_LOCKED
73from ._common import STATUS_PARKED
74from ._common import STATUS_RUNNING
75from ._common import STATUS_SLEEPING
76from ._common import STATUS_STOPPED
77from ._common import STATUS_TRACING_STOP
78from ._common import STATUS_WAITING
79from ._common import STATUS_WAKING
80from ._common import STATUS_ZOMBIE
81from ._common import SUNOS
82from ._common import WINDOWS
83from ._common import AccessDenied
84from ._common import Error
85from ._common import NoSuchProcess
86from ._common import TimeoutExpired
87from ._common import ZombieProcess
88from ._common import memoize_when_activated
89from ._common import wrap_numbers as _wrap_numbers
90from ._compat import PY3 as _PY3
91from ._compat import PermissionError
92from ._compat import ProcessLookupError
93from ._compat import SubprocessTimeoutExpired as _SubprocessTimeoutExpired
94from ._compat import long
97if LINUX:
98 # This is public API and it will be retrieved from _pslinux.py
99 # via sys.modules.
100 PROCFS_PATH = "/proc"
102 from . import _pslinux as _psplatform
103 from ._pslinux import IOPRIO_CLASS_BE # NOQA
104 from ._pslinux import IOPRIO_CLASS_IDLE # NOQA
105 from ._pslinux import IOPRIO_CLASS_NONE # NOQA
106 from ._pslinux import IOPRIO_CLASS_RT # NOQA
108elif WINDOWS:
109 from . import _pswindows as _psplatform
110 from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # NOQA
111 from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # NOQA
112 from ._psutil_windows import HIGH_PRIORITY_CLASS # NOQA
113 from ._psutil_windows import IDLE_PRIORITY_CLASS # NOQA
114 from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA
115 from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA
116 from ._pswindows import CONN_DELETE_TCB # NOQA
117 from ._pswindows import IOPRIO_HIGH # NOQA
118 from ._pswindows import IOPRIO_LOW # NOQA
119 from ._pswindows import IOPRIO_NORMAL # NOQA
120 from ._pswindows import IOPRIO_VERYLOW # NOQA
122elif MACOS:
123 from . import _psosx as _psplatform
125elif BSD:
126 from . import _psbsd as _psplatform
128elif SUNOS:
129 from . import _pssunos as _psplatform
130 from ._pssunos import CONN_BOUND # NOQA
131 from ._pssunos import CONN_IDLE # NOQA
133 # This is public writable API which is read from _pslinux.py and
134 # _pssunos.py via sys.modules.
135 PROCFS_PATH = "/proc"
137elif AIX:
138 from . import _psaix as _psplatform
140 # This is public API and it will be retrieved from _pslinux.py
141 # via sys.modules.
142 PROCFS_PATH = "/proc"
144else: # pragma: no cover
145 raise NotImplementedError('platform %s is not supported' % sys.platform)
148__all__ = [
149 # exceptions
150 "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied",
151 "TimeoutExpired",
153 # constants
154 "version_info", "__version__",
156 "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
157 "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
158 "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
159 "STATUS_PARKED",
161 "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
162 "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
163 "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE",
164 # "CONN_IDLE", "CONN_BOUND",
166 "AF_LINK",
168 "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN",
170 "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
172 "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
173 "SUNOS", "WINDOWS", "AIX",
175 # "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA",
176 # "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE",
177 # "RLIMIT_NPROC", "RLIMIT_RSS", "RLIMIT_STACK", "RLIMIT_MSGQUEUE",
178 # "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIMIT_SIGPENDING",
180 # classes
181 "Process", "Popen",
183 # functions
184 "pid_exists", "pids", "process_iter", "wait_procs", # proc
185 "virtual_memory", "swap_memory", # memory
186 "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu
187 "cpu_stats", # "cpu_freq", "getloadavg"
188 "net_io_counters", "net_connections", "net_if_addrs", # network
189 "net_if_stats",
190 "disk_io_counters", "disk_partitions", "disk_usage", # disk
191 # "sensors_temperatures", "sensors_battery", "sensors_fans" # sensors
192 "users", "boot_time", # others
193]
196__all__.extend(_psplatform.__extra__all__)
198# Linux, FreeBSD
199if hasattr(_psplatform.Process, "rlimit"):
200 # Populate global namespace with RLIM* constants.
201 from . import _psutil_posix
203 _globals = globals()
204 _name = None
205 for _name in dir(_psutil_posix):
206 if _name.startswith('RLIM') and _name.isupper():
207 _globals[_name] = getattr(_psutil_posix, _name)
208 __all__.append(_name)
209 del _globals, _name
211AF_LINK = _psplatform.AF_LINK
213__author__ = "Giampaolo Rodola'"
214__version__ = "5.9.5"
215version_info = tuple([int(num) for num in __version__.split('.')])
217_timer = getattr(time, 'monotonic', time.time)
218_TOTAL_PHYMEM = None
219_LOWEST_PID = None
220_SENTINEL = object()
222# Sanity check in case the user messed up with psutil installation
223# or did something weird with sys.path. In this case we might end
224# up importing a python module using a C extension module which
225# was compiled for a different version of psutil.
226# We want to prevent that by failing sooner rather than later.
227# See: https://github.com/giampaolo/psutil/issues/564
228if (int(__version__.replace('.', '')) !=
229 getattr(_psplatform.cext, 'version', None)):
230 msg = "version conflict: %r C extension module was built for another " \
231 "version of psutil" % _psplatform.cext.__file__
232 if hasattr(_psplatform.cext, 'version'):
233 msg += " (%s instead of %s)" % (
234 '.'.join([x for x in str(_psplatform.cext.version)]), __version__)
235 else:
236 msg += " (different than %s)" % __version__
237 msg += "; you may try to 'pip uninstall psutil', manually remove %s" % (
238 getattr(_psplatform.cext, "__file__",
239 "the existing psutil install directory"))
240 msg += " or clean the virtual env somehow, then reinstall"
241 raise ImportError(msg)
244# =====================================================================
245# --- Utils
246# =====================================================================
249if hasattr(_psplatform, 'ppid_map'):
250 # Faster version (Windows and Linux).
251 _ppid_map = _psplatform.ppid_map
252else: # pragma: no cover
253 def _ppid_map():
254 """Return a {pid: ppid, ...} dict for all running processes in
255 one shot. Used to speed up Process.children().
256 """
257 ret = {}
258 for pid in pids():
259 try:
260 ret[pid] = _psplatform.Process(pid).ppid()
261 except (NoSuchProcess, ZombieProcess):
262 pass
263 return ret
266def _assert_pid_not_reused(fun):
267 """Decorator which raises NoSuchProcess in case a process is no
268 longer running or its PID has been reused.
269 """
270 @functools.wraps(fun)
271 def wrapper(self, *args, **kwargs):
272 if not self.is_running():
273 if self._pid_reused:
274 msg = "process no longer exists and its PID has been reused"
275 else:
276 msg = None
277 raise NoSuchProcess(self.pid, self._name, msg=msg)
278 return fun(self, *args, **kwargs)
279 return wrapper
282def _pprint_secs(secs):
283 """Format seconds in a human readable form."""
284 now = time.time()
285 secs_ago = int(now - secs)
286 if secs_ago < 60 * 60 * 24:
287 fmt = "%H:%M:%S"
288 else:
289 fmt = "%Y-%m-%d %H:%M:%S"
290 return datetime.datetime.fromtimestamp(secs).strftime(fmt)
293# =====================================================================
294# --- Process class
295# =====================================================================
298class Process(object):
299 """Represents an OS process with the given PID.
300 If PID is omitted current process PID (os.getpid()) is used.
301 Raise NoSuchProcess if PID does not exist.
303 Note that most of the methods of this class do not make sure
304 the PID of the process being queried has been reused over time.
305 That means you might end up retrieving an information referring
306 to another process in case the original one this instance
307 refers to is gone in the meantime.
309 The only exceptions for which process identity is pre-emptively
310 checked and guaranteed are:
312 - parent()
313 - children()
314 - nice() (set)
315 - ionice() (set)
316 - rlimit() (set)
317 - cpu_affinity (set)
318 - suspend()
319 - resume()
320 - send_signal()
321 - terminate()
322 - kill()
324 To prevent this problem for all other methods you can:
325 - use is_running() before querying the process
326 - if you're continuously iterating over a set of Process
327 instances use process_iter() which pre-emptively checks
328 process identity for every yielded instance
329 """
331 def __init__(self, pid=None):
332 self._init(pid)
334 def _init(self, pid, _ignore_nsp=False):
335 if pid is None:
336 pid = os.getpid()
337 else:
338 if not _PY3 and not isinstance(pid, (int, long)):
339 raise TypeError('pid must be an integer (got %r)' % pid)
340 if pid < 0:
341 raise ValueError('pid must be a positive integer (got %s)'
342 % pid)
343 self._pid = pid
344 self._name = None
345 self._exe = None
346 self._create_time = None
347 self._gone = False
348 self._pid_reused = False
349 self._hash = None
350 self._lock = threading.RLock()
351 # used for caching on Windows only (on POSIX ppid may change)
352 self._ppid = None
353 # platform-specific modules define an _psplatform.Process
354 # implementation class
355 self._proc = _psplatform.Process(pid)
356 self._last_sys_cpu_times = None
357 self._last_proc_cpu_times = None
358 self._exitcode = _SENTINEL
359 # cache creation time for later use in is_running() method
360 try:
361 self.create_time()
362 except AccessDenied:
363 # We should never get here as AFAIK we're able to get
364 # process creation time on all platforms even as a
365 # limited user.
366 pass
367 except ZombieProcess:
368 # Zombies can still be queried by this class (although
369 # not always) and pids() return them so just go on.
370 pass
371 except NoSuchProcess:
372 if not _ignore_nsp:
373 raise NoSuchProcess(pid, msg='process PID not found')
374 else:
375 self._gone = True
376 # This pair is supposed to identify a Process instance
377 # univocally over time (the PID alone is not enough as
378 # it might refer to a process whose PID has been reused).
379 # This will be used later in __eq__() and is_running().
380 self._ident = (self.pid, self._create_time)
382 def __str__(self):
383 info = collections.OrderedDict()
384 info["pid"] = self.pid
385 if self._name:
386 info['name'] = self._name
387 with self.oneshot():
388 try:
389 info["name"] = self.name()
390 info["status"] = self.status()
391 except ZombieProcess:
392 info["status"] = "zombie"
393 except NoSuchProcess:
394 info["status"] = "terminated"
395 except AccessDenied:
396 pass
397 if self._exitcode not in (_SENTINEL, None):
398 info["exitcode"] = self._exitcode
399 if self._create_time:
400 info['started'] = _pprint_secs(self._create_time)
401 return "%s.%s(%s)" % (
402 self.__class__.__module__,
403 self.__class__.__name__,
404 ", ".join(["%s=%r" % (k, v) for k, v in info.items()]))
406 __repr__ = __str__
408 def __eq__(self, other):
409 # Test for equality with another Process object based
410 # on PID and creation time.
411 if not isinstance(other, Process):
412 return NotImplemented
413 return self._ident == other._ident
415 def __ne__(self, other):
416 return not self == other
418 def __hash__(self):
419 if self._hash is None:
420 self._hash = hash(self._ident)
421 return self._hash
423 @property
424 def pid(self):
425 """The process PID."""
426 return self._pid
428 # --- utility methods
430 @contextlib.contextmanager
431 def oneshot(self):
432 """Utility context manager which considerably speeds up the
433 retrieval of multiple process information at the same time.
435 Internally different process info (e.g. name, ppid, uids,
436 gids, ...) may be fetched by using the same routine, but
437 only one information is returned and the others are discarded.
438 When using this context manager the internal routine is
439 executed once (in the example below on name()) and the
440 other info are cached.
442 The cache is cleared when exiting the context manager block.
443 The advice is to use this every time you retrieve more than
444 one information about the process. If you're lucky, you'll
445 get a hell of a speedup.
447 >>> import psutil
448 >>> p = psutil.Process()
449 >>> with p.oneshot():
450 ... p.name() # collect multiple info
451 ... p.cpu_times() # return cached value
452 ... p.cpu_percent() # return cached value
453 ... p.create_time() # return cached value
454 ...
455 >>>
456 """
457 with self._lock:
458 if hasattr(self, "_cache"):
459 # NOOP: this covers the use case where the user enters the
460 # context twice:
461 #
462 # >>> with p.oneshot():
463 # ... with p.oneshot():
464 # ...
465 #
466 # Also, since as_dict() internally uses oneshot()
467 # I expect that the code below will be a pretty common
468 # "mistake" that the user will make, so let's guard
469 # against that:
470 #
471 # >>> with p.oneshot():
472 # ... p.as_dict()
473 # ...
474 yield
475 else:
476 try:
477 # cached in case cpu_percent() is used
478 self.cpu_times.cache_activate(self)
479 # cached in case memory_percent() is used
480 self.memory_info.cache_activate(self)
481 # cached in case parent() is used
482 self.ppid.cache_activate(self)
483 # cached in case username() is used
484 if POSIX:
485 self.uids.cache_activate(self)
486 # specific implementation cache
487 self._proc.oneshot_enter()
488 yield
489 finally:
490 self.cpu_times.cache_deactivate(self)
491 self.memory_info.cache_deactivate(self)
492 self.ppid.cache_deactivate(self)
493 if POSIX:
494 self.uids.cache_deactivate(self)
495 self._proc.oneshot_exit()
497 def as_dict(self, attrs=None, ad_value=None):
498 """Utility method returning process information as a
499 hashable dictionary.
500 If *attrs* is specified it must be a list of strings
501 reflecting available Process class' attribute names
502 (e.g. ['cpu_times', 'name']) else all public (read
503 only) attributes are assumed.
504 *ad_value* is the value which gets assigned in case
505 AccessDenied or ZombieProcess exception is raised when
506 retrieving that particular process information.
507 """
508 valid_names = _as_dict_attrnames
509 if attrs is not None:
510 if not isinstance(attrs, (list, tuple, set, frozenset)):
511 raise TypeError("invalid attrs type %s" % type(attrs))
512 attrs = set(attrs)
513 invalid_names = attrs - valid_names
514 if invalid_names:
515 raise ValueError("invalid attr name%s %s" % (
516 "s" if len(invalid_names) > 1 else "",
517 ", ".join(map(repr, invalid_names))))
519 retdict = {}
520 ls = attrs or valid_names
521 with self.oneshot():
522 for name in ls:
523 try:
524 if name == 'pid':
525 ret = self.pid
526 else:
527 meth = getattr(self, name)
528 ret = meth()
529 except (AccessDenied, ZombieProcess):
530 ret = ad_value
531 except NotImplementedError:
532 # in case of not implemented functionality (may happen
533 # on old or exotic systems) we want to crash only if
534 # the user explicitly asked for that particular attr
535 if attrs:
536 raise
537 continue
538 retdict[name] = ret
539 return retdict
541 def parent(self):
542 """Return the parent process as a Process object pre-emptively
543 checking whether PID has been reused.
544 If no parent is known return None.
545 """
546 lowest_pid = _LOWEST_PID if _LOWEST_PID is not None else pids()[0]
547 if self.pid == lowest_pid:
548 return None
549 ppid = self.ppid()
550 if ppid is not None:
551 ctime = self.create_time()
552 try:
553 parent = Process(ppid)
554 if parent.create_time() <= ctime:
555 return parent
556 # ...else ppid has been reused by another process
557 except NoSuchProcess:
558 pass
560 def parents(self):
561 """Return the parents of this process as a list of Process
562 instances. If no parents are known return an empty list.
563 """
564 parents = []
565 proc = self.parent()
566 while proc is not None:
567 parents.append(proc)
568 proc = proc.parent()
569 return parents
571 def is_running(self):
572 """Return whether this process is running.
573 It also checks if PID has been reused by another process in
574 which case return False.
575 """
576 if self._gone or self._pid_reused:
577 return False
578 try:
579 # Checking if PID is alive is not enough as the PID might
580 # have been reused by another process: we also want to
581 # verify process identity.
582 # Process identity / uniqueness over time is guaranteed by
583 # (PID + creation time) and that is verified in __eq__.
584 self._pid_reused = self != Process(self.pid)
585 return not self._pid_reused
586 except ZombieProcess:
587 # We should never get here as it's already handled in
588 # Process.__init__; here just for extra safety.
589 return True
590 except NoSuchProcess:
591 self._gone = True
592 return False
594 # --- actual API
596 @memoize_when_activated
597 def ppid(self):
598 """The process parent PID.
599 On Windows the return value is cached after first call.
600 """
601 # On POSIX we don't want to cache the ppid as it may unexpectedly
602 # change to 1 (init) in case this process turns into a zombie:
603 # https://github.com/giampaolo/psutil/issues/321
604 # http://stackoverflow.com/questions/356722/
606 # XXX should we check creation time here rather than in
607 # Process.parent()?
608 if POSIX:
609 return self._proc.ppid()
610 else: # pragma: no cover
611 self._ppid = self._ppid or self._proc.ppid()
612 return self._ppid
614 def name(self):
615 """The process name. The return value is cached after first call."""
616 # Process name is only cached on Windows as on POSIX it may
617 # change, see:
618 # https://github.com/giampaolo/psutil/issues/692
619 if WINDOWS and self._name is not None:
620 return self._name
621 name = self._proc.name()
622 if POSIX and len(name) >= 15:
623 # On UNIX the name gets truncated to the first 15 characters.
624 # If it matches the first part of the cmdline we return that
625 # one instead because it's usually more explicative.
626 # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
627 try:
628 cmdline = self.cmdline()
629 except (AccessDenied, ZombieProcess):
630 # Just pass and return the truncated name: it's better
631 # than nothing. Note: there are actual cases where a
632 # zombie process can return a name() but not a
633 # cmdline(), see:
634 # https://github.com/giampaolo/psutil/issues/2239
635 pass
636 else:
637 if cmdline:
638 extended_name = os.path.basename(cmdline[0])
639 if extended_name.startswith(name):
640 name = extended_name
641 self._name = name
642 self._proc._name = name
643 return name
645 def exe(self):
646 """The process executable as an absolute path.
647 May also be an empty string.
648 The return value is cached after first call.
649 """
650 def guess_it(fallback):
651 # try to guess exe from cmdline[0] in absence of a native
652 # exe representation
653 cmdline = self.cmdline()
654 if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
655 exe = cmdline[0] # the possible exe
656 # Attempt to guess only in case of an absolute path.
657 # It is not safe otherwise as the process might have
658 # changed cwd.
659 if (os.path.isabs(exe) and
660 os.path.isfile(exe) and
661 os.access(exe, os.X_OK)):
662 return exe
663 if isinstance(fallback, AccessDenied):
664 raise fallback
665 return fallback
667 if self._exe is None:
668 try:
669 exe = self._proc.exe()
670 except AccessDenied as err:
671 return guess_it(fallback=err)
672 else:
673 if not exe:
674 # underlying implementation can legitimately return an
675 # empty string; if that's the case we don't want to
676 # raise AD while guessing from the cmdline
677 try:
678 exe = guess_it(fallback=exe)
679 except AccessDenied:
680 pass
681 self._exe = exe
682 return self._exe
684 def cmdline(self):
685 """The command line this process has been called with."""
686 return self._proc.cmdline()
688 def status(self):
689 """The process current status as a STATUS_* constant."""
690 try:
691 return self._proc.status()
692 except ZombieProcess:
693 return STATUS_ZOMBIE
695 def username(self):
696 """The name of the user that owns the process.
697 On UNIX this is calculated by using *real* process uid.
698 """
699 if POSIX:
700 if pwd is None:
701 # might happen if python was installed from sources
702 raise ImportError(
703 "requires pwd module shipped with standard python")
704 real_uid = self.uids().real
705 try:
706 return pwd.getpwuid(real_uid).pw_name
707 except KeyError:
708 # the uid can't be resolved by the system
709 return str(real_uid)
710 else:
711 return self._proc.username()
713 def create_time(self):
714 """The process creation time as a floating point number
715 expressed in seconds since the epoch.
716 The return value is cached after first call.
717 """
718 if self._create_time is None:
719 self._create_time = self._proc.create_time()
720 return self._create_time
722 def cwd(self):
723 """Process current working directory as an absolute path."""
724 return self._proc.cwd()
726 def nice(self, value=None):
727 """Get or set process niceness (priority)."""
728 if value is None:
729 return self._proc.nice_get()
730 else:
731 if not self.is_running():
732 raise NoSuchProcess(self.pid, self._name)
733 self._proc.nice_set(value)
735 if POSIX:
737 @memoize_when_activated
738 def uids(self):
739 """Return process UIDs as a (real, effective, saved)
740 namedtuple.
741 """
742 return self._proc.uids()
744 def gids(self):
745 """Return process GIDs as a (real, effective, saved)
746 namedtuple.
747 """
748 return self._proc.gids()
750 def terminal(self):
751 """The terminal associated with this process, if any,
752 else None.
753 """
754 return self._proc.terminal()
756 def num_fds(self):
757 """Return the number of file descriptors opened by this
758 process (POSIX only).
759 """
760 return self._proc.num_fds()
762 # Linux, BSD, AIX and Windows only
763 if hasattr(_psplatform.Process, "io_counters"):
765 def io_counters(self):
766 """Return process I/O statistics as a
767 (read_count, write_count, read_bytes, write_bytes)
768 namedtuple.
769 Those are the number of read/write calls performed and the
770 amount of bytes read and written by the process.
771 """
772 return self._proc.io_counters()
774 # Linux and Windows
775 if hasattr(_psplatform.Process, "ionice_get"):
777 def ionice(self, ioclass=None, value=None):
778 """Get or set process I/O niceness (priority).
780 On Linux *ioclass* is one of the IOPRIO_CLASS_* constants.
781 *value* is a number which goes from 0 to 7. The higher the
782 value, the lower the I/O priority of the process.
784 On Windows only *ioclass* is used and it can be set to 2
785 (normal), 1 (low) or 0 (very low).
787 Available on Linux and Windows > Vista only.
788 """
789 if ioclass is None:
790 if value is not None:
791 raise ValueError("'ioclass' argument must be specified")
792 return self._proc.ionice_get()
793 else:
794 return self._proc.ionice_set(ioclass, value)
796 # Linux / FreeBSD only
797 if hasattr(_psplatform.Process, "rlimit"):
799 def rlimit(self, resource, limits=None):
800 """Get or set process resource limits as a (soft, hard)
801 tuple.
803 *resource* is one of the RLIMIT_* constants.
804 *limits* is supposed to be a (soft, hard) tuple.
806 See "man prlimit" for further info.
807 Available on Linux and FreeBSD only.
808 """
809 return self._proc.rlimit(resource, limits)
811 # Windows, Linux and FreeBSD only
812 if hasattr(_psplatform.Process, "cpu_affinity_get"):
814 def cpu_affinity(self, cpus=None):
815 """Get or set process CPU affinity.
816 If specified, *cpus* must be a list of CPUs for which you
817 want to set the affinity (e.g. [0, 1]).
818 If an empty list is passed, all egible CPUs are assumed
819 (and set).
820 (Windows, Linux and BSD only).
821 """
822 if cpus is None:
823 return sorted(set(self._proc.cpu_affinity_get()))
824 else:
825 if not cpus:
826 if hasattr(self._proc, "_get_eligible_cpus"):
827 cpus = self._proc._get_eligible_cpus()
828 else:
829 cpus = tuple(range(len(cpu_times(percpu=True))))
830 self._proc.cpu_affinity_set(list(set(cpus)))
832 # Linux, FreeBSD, SunOS
833 if hasattr(_psplatform.Process, "cpu_num"):
835 def cpu_num(self):
836 """Return what CPU this process is currently running on.
837 The returned number should be <= psutil.cpu_count()
838 and <= len(psutil.cpu_percent(percpu=True)).
839 It may be used in conjunction with
840 psutil.cpu_percent(percpu=True) to observe the system
841 workload distributed across CPUs.
842 """
843 return self._proc.cpu_num()
845 # All platforms has it, but maybe not in the future.
846 if hasattr(_psplatform.Process, "environ"):
848 def environ(self):
849 """The environment variables of the process as a dict. Note: this
850 might not reflect changes made after the process started. """
851 return self._proc.environ()
853 if WINDOWS:
855 def num_handles(self):
856 """Return the number of handles opened by this process
857 (Windows only).
858 """
859 return self._proc.num_handles()
861 def num_ctx_switches(self):
862 """Return the number of voluntary and involuntary context
863 switches performed by this process.
864 """
865 return self._proc.num_ctx_switches()
867 def num_threads(self):
868 """Return the number of threads used by this process."""
869 return self._proc.num_threads()
871 if hasattr(_psplatform.Process, "threads"):
873 def threads(self):
874 """Return threads opened by process as a list of
875 (id, user_time, system_time) namedtuples representing
876 thread id and thread CPU times (user/system).
877 On OpenBSD this method requires root access.
878 """
879 return self._proc.threads()
881 @_assert_pid_not_reused
882 def children(self, recursive=False):
883 """Return the children of this process as a list of Process
884 instances, pre-emptively checking whether PID has been reused.
885 If *recursive* is True return all the parent descendants.
887 Example (A == this process):
889 A ─┐
890 │
891 ├─ B (child) ─┐
892 │ └─ X (grandchild) ─┐
893 │ └─ Y (great grandchild)
894 ├─ C (child)
895 └─ D (child)
897 >>> import psutil
898 >>> p = psutil.Process()
899 >>> p.children()
900 B, C, D
901 >>> p.children(recursive=True)
902 B, X, Y, C, D
904 Note that in the example above if process X disappears
905 process Y won't be listed as the reference to process A
906 is lost.
907 """
908 ppid_map = _ppid_map()
909 ret = []
910 if not recursive:
911 for pid, ppid in ppid_map.items():
912 if ppid == self.pid:
913 try:
914 child = Process(pid)
915 # if child happens to be older than its parent
916 # (self) it means child's PID has been reused
917 if self.create_time() <= child.create_time():
918 ret.append(child)
919 except (NoSuchProcess, ZombieProcess):
920 pass
921 else:
922 # Construct a {pid: [child pids]} dict
923 reverse_ppid_map = collections.defaultdict(list)
924 for pid, ppid in ppid_map.items():
925 reverse_ppid_map[ppid].append(pid)
926 # Recursively traverse that dict, starting from self.pid,
927 # such that we only call Process() on actual children
928 seen = set()
929 stack = [self.pid]
930 while stack:
931 pid = stack.pop()
932 if pid in seen:
933 # Since pids can be reused while the ppid_map is
934 # constructed, there may be rare instances where
935 # there's a cycle in the recorded process "tree".
936 continue
937 seen.add(pid)
938 for child_pid in reverse_ppid_map[pid]:
939 try:
940 child = Process(child_pid)
941 # if child happens to be older than its parent
942 # (self) it means child's PID has been reused
943 intime = self.create_time() <= child.create_time()
944 if intime:
945 ret.append(child)
946 stack.append(child_pid)
947 except (NoSuchProcess, ZombieProcess):
948 pass
949 return ret
951 def cpu_percent(self, interval=None):
952 """Return a float representing the current process CPU
953 utilization as a percentage.
955 When *interval* is 0.0 or None (default) compares process times
956 to system CPU times elapsed since last call, returning
957 immediately (non-blocking). That means that the first time
958 this is called it will return a meaningful 0.0 value.
960 When *interval* is > 0.0 compares process times to system CPU
961 times elapsed before and after the interval (blocking).
963 In this case is recommended for accuracy that this function
964 be called with at least 0.1 seconds between calls.
966 A value > 100.0 can be returned in case of processes running
967 multiple threads on different CPU cores.
969 The returned value is explicitly NOT split evenly between
970 all available logical CPUs. This means that a busy loop process
971 running on a system with 2 logical CPUs will be reported as
972 having 100% CPU utilization instead of 50%.
974 Examples:
976 >>> import psutil
977 >>> p = psutil.Process(os.getpid())
978 >>> # blocking
979 >>> p.cpu_percent(interval=1)
980 2.0
981 >>> # non-blocking (percentage since last call)
982 >>> p.cpu_percent(interval=None)
983 2.9
984 >>>
985 """
986 blocking = interval is not None and interval > 0.0
987 if interval is not None and interval < 0:
988 raise ValueError("interval is not positive (got %r)" % interval)
989 num_cpus = cpu_count() or 1
991 def timer():
992 return _timer() * num_cpus
994 if blocking:
995 st1 = timer()
996 pt1 = self._proc.cpu_times()
997 time.sleep(interval)
998 st2 = timer()
999 pt2 = self._proc.cpu_times()
1000 else:
1001 st1 = self._last_sys_cpu_times
1002 pt1 = self._last_proc_cpu_times
1003 st2 = timer()
1004 pt2 = self._proc.cpu_times()
1005 if st1 is None or pt1 is None:
1006 self._last_sys_cpu_times = st2
1007 self._last_proc_cpu_times = pt2
1008 return 0.0
1010 delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
1011 delta_time = st2 - st1
1012 # reset values for next call in case of interval == None
1013 self._last_sys_cpu_times = st2
1014 self._last_proc_cpu_times = pt2
1016 try:
1017 # This is the utilization split evenly between all CPUs.
1018 # E.g. a busy loop process on a 2-CPU-cores system at this
1019 # point is reported as 50% instead of 100%.
1020 overall_cpus_percent = ((delta_proc / delta_time) * 100)
1021 except ZeroDivisionError:
1022 # interval was too low
1023 return 0.0
1024 else:
1025 # Note 1:
1026 # in order to emulate "top" we multiply the value for the num
1027 # of CPU cores. This way the busy process will be reported as
1028 # having 100% (or more) usage.
1029 #
1030 # Note 2:
1031 # taskmgr.exe on Windows differs in that it will show 50%
1032 # instead.
1033 #
1034 # Note 3:
1035 # a percentage > 100 is legitimate as it can result from a
1036 # process with multiple threads running on different CPU
1037 # cores (top does the same), see:
1038 # http://stackoverflow.com/questions/1032357
1039 # https://github.com/giampaolo/psutil/issues/474
1040 single_cpu_percent = overall_cpus_percent * num_cpus
1041 return round(single_cpu_percent, 1)
1043 @memoize_when_activated
1044 def cpu_times(self):
1045 """Return a (user, system, children_user, children_system)
1046 namedtuple representing the accumulated process time, in
1047 seconds.
1048 This is similar to os.times() but per-process.
1049 On macOS and Windows children_user and children_system are
1050 always set to 0.
1051 """
1052 return self._proc.cpu_times()
1054 @memoize_when_activated
1055 def memory_info(self):
1056 """Return a namedtuple with variable fields depending on the
1057 platform, representing memory information about the process.
1059 The "portable" fields available on all platforms are `rss` and `vms`.
1061 All numbers are expressed in bytes.
1062 """
1063 return self._proc.memory_info()
1065 @_common.deprecated_method(replacement="memory_info")
1066 def memory_info_ex(self):
1067 return self.memory_info()
1069 def memory_full_info(self):
1070 """This method returns the same information as memory_info(),
1071 plus, on some platform (Linux, macOS, Windows), also provides
1072 additional metrics (USS, PSS and swap).
1073 The additional metrics provide a better representation of actual
1074 process memory usage.
1076 Namely USS is the memory which is unique to a process and which
1077 would be freed if the process was terminated right now.
1079 It does so by passing through the whole process address.
1080 As such it usually requires higher user privileges than
1081 memory_info() and is considerably slower.
1082 """
1083 return self._proc.memory_full_info()
1085 def memory_percent(self, memtype="rss"):
1086 """Compare process memory to total physical system memory and
1087 calculate process memory utilization as a percentage.
1088 *memtype* argument is a string that dictates what type of
1089 process memory you want to compare against (defaults to "rss").
1090 The list of available strings can be obtained like this:
1092 >>> psutil.Process().memory_info()._fields
1093 ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss')
1094 """
1095 valid_types = list(_psplatform.pfullmem._fields)
1096 if memtype not in valid_types:
1097 raise ValueError("invalid memtype %r; valid types are %r" % (
1098 memtype, tuple(valid_types)))
1099 fun = self.memory_info if memtype in _psplatform.pmem._fields else \
1100 self.memory_full_info
1101 metrics = fun()
1102 value = getattr(metrics, memtype)
1104 # use cached value if available
1105 total_phymem = _TOTAL_PHYMEM or virtual_memory().total
1106 if not total_phymem > 0:
1107 # we should never get here
1108 raise ValueError(
1109 "can't calculate process memory percent because "
1110 "total physical system memory is not positive (%r)"
1111 % total_phymem)
1112 return (value / float(total_phymem)) * 100
1114 if hasattr(_psplatform.Process, "memory_maps"):
1115 def memory_maps(self, grouped=True):
1116 """Return process' mapped memory regions as a list of namedtuples
1117 whose fields are variable depending on the platform.
1119 If *grouped* is True the mapped regions with the same 'path'
1120 are grouped together and the different memory fields are summed.
1122 If *grouped* is False every mapped region is shown as a single
1123 entity and the namedtuple will also include the mapped region's
1124 address space ('addr') and permission set ('perms').
1125 """
1126 it = self._proc.memory_maps()
1127 if grouped:
1128 d = {}
1129 for tupl in it:
1130 path = tupl[2]
1131 nums = tupl[3:]
1132 try:
1133 d[path] = map(lambda x, y: x + y, d[path], nums)
1134 except KeyError:
1135 d[path] = nums
1136 nt = _psplatform.pmmap_grouped
1137 return [nt(path, *d[path]) for path in d] # NOQA
1138 else:
1139 nt = _psplatform.pmmap_ext
1140 return [nt(*x) for x in it]
1142 def open_files(self):
1143 """Return files opened by process as a list of
1144 (path, fd) namedtuples including the absolute file name
1145 and file descriptor number.
1146 """
1147 return self._proc.open_files()
1149 def connections(self, kind='inet'):
1150 """Return socket connections opened by process as a list of
1151 (fd, family, type, laddr, raddr, status) namedtuples.
1152 The *kind* parameter filters for connections that match the
1153 following criteria:
1155 +------------+----------------------------------------------------+
1156 | Kind Value | Connections using |
1157 +------------+----------------------------------------------------+
1158 | inet | IPv4 and IPv6 |
1159 | inet4 | IPv4 |
1160 | inet6 | IPv6 |
1161 | tcp | TCP |
1162 | tcp4 | TCP over IPv4 |
1163 | tcp6 | TCP over IPv6 |
1164 | udp | UDP |
1165 | udp4 | UDP over IPv4 |
1166 | udp6 | UDP over IPv6 |
1167 | unix | UNIX socket (both UDP and TCP protocols) |
1168 | all | the sum of all the possible families and protocols |
1169 +------------+----------------------------------------------------+
1170 """
1171 return self._proc.connections(kind)
1173 # --- signals
1175 if POSIX:
1176 def _send_signal(self, sig):
1177 assert not self.pid < 0, self.pid
1178 if self.pid == 0:
1179 # see "man 2 kill"
1180 raise ValueError(
1181 "preventing sending signal to process with PID 0 as it "
1182 "would affect every process in the process group of the "
1183 "calling process (os.getpid()) instead of PID 0")
1184 try:
1185 os.kill(self.pid, sig)
1186 except ProcessLookupError:
1187 if OPENBSD and pid_exists(self.pid):
1188 # We do this because os.kill() lies in case of
1189 # zombie processes.
1190 raise ZombieProcess(self.pid, self._name, self._ppid)
1191 else:
1192 self._gone = True
1193 raise NoSuchProcess(self.pid, self._name)
1194 except PermissionError:
1195 raise AccessDenied(self.pid, self._name)
1197 @_assert_pid_not_reused
1198 def send_signal(self, sig):
1199 """Send a signal *sig* to process pre-emptively checking
1200 whether PID has been reused (see signal module constants) .
1201 On Windows only SIGTERM is valid and is treated as an alias
1202 for kill().
1203 """
1204 if POSIX:
1205 self._send_signal(sig)
1206 else: # pragma: no cover
1207 self._proc.send_signal(sig)
1209 @_assert_pid_not_reused
1210 def suspend(self):
1211 """Suspend process execution with SIGSTOP pre-emptively checking
1212 whether PID has been reused.
1213 On Windows this has the effect of suspending all process threads.
1214 """
1215 if POSIX:
1216 self._send_signal(signal.SIGSTOP)
1217 else: # pragma: no cover
1218 self._proc.suspend()
1220 @_assert_pid_not_reused
1221 def resume(self):
1222 """Resume process execution with SIGCONT pre-emptively checking
1223 whether PID has been reused.
1224 On Windows this has the effect of resuming all process threads.
1225 """
1226 if POSIX:
1227 self._send_signal(signal.SIGCONT)
1228 else: # pragma: no cover
1229 self._proc.resume()
1231 @_assert_pid_not_reused
1232 def terminate(self):
1233 """Terminate the process with SIGTERM pre-emptively checking
1234 whether PID has been reused.
1235 On Windows this is an alias for kill().
1236 """
1237 if POSIX:
1238 self._send_signal(signal.SIGTERM)
1239 else: # pragma: no cover
1240 self._proc.kill()
1242 @_assert_pid_not_reused
1243 def kill(self):
1244 """Kill the current process with SIGKILL pre-emptively checking
1245 whether PID has been reused.
1246 """
1247 if POSIX:
1248 self._send_signal(signal.SIGKILL)
1249 else: # pragma: no cover
1250 self._proc.kill()
1252 def wait(self, timeout=None):
1253 """Wait for process to terminate and, if process is a children
1254 of os.getpid(), also return its exit code, else None.
1255 On Windows there's no such limitation (exit code is always
1256 returned).
1258 If the process is already terminated immediately return None
1259 instead of raising NoSuchProcess.
1261 If *timeout* (in seconds) is specified and process is still
1262 alive raise TimeoutExpired.
1264 To wait for multiple Process(es) use psutil.wait_procs().
1265 """
1266 if timeout is not None and not timeout >= 0:
1267 raise ValueError("timeout must be a positive integer")
1268 if self._exitcode is not _SENTINEL:
1269 return self._exitcode
1270 self._exitcode = self._proc.wait(timeout)
1271 return self._exitcode
1274# The valid attr names which can be processed by Process.as_dict().
1275_as_dict_attrnames = set(
1276 [x for x in dir(Process) if not x.startswith('_') and x not in
1277 ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
1278 'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit',
1279 'memory_info_ex', 'oneshot']])
1282# =====================================================================
1283# --- Popen class
1284# =====================================================================
1287class Popen(Process):
1288 """Same as subprocess.Popen, but in addition it provides all
1289 psutil.Process methods in a single class.
1290 For the following methods which are common to both classes, psutil
1291 implementation takes precedence:
1293 * send_signal()
1294 * terminate()
1295 * kill()
1297 This is done in order to avoid killing another process in case its
1298 PID has been reused, fixing BPO-6973.
1300 >>> import psutil
1301 >>> from subprocess import PIPE
1302 >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE)
1303 >>> p.name()
1304 'python'
1305 >>> p.uids()
1306 user(real=1000, effective=1000, saved=1000)
1307 >>> p.username()
1308 'giampaolo'
1309 >>> p.communicate()
1310 ('hi\n', None)
1311 >>> p.terminate()
1312 >>> p.wait(timeout=2)
1313 0
1314 >>>
1315 """
1317 def __init__(self, *args, **kwargs):
1318 # Explicitly avoid to raise NoSuchProcess in case the process
1319 # spawned by subprocess.Popen terminates too quickly, see:
1320 # https://github.com/giampaolo/psutil/issues/193
1321 self.__subproc = subprocess.Popen(*args, **kwargs)
1322 self._init(self.__subproc.pid, _ignore_nsp=True)
1324 def __dir__(self):
1325 return sorted(set(dir(Popen) + dir(subprocess.Popen)))
1327 def __enter__(self):
1328 if hasattr(self.__subproc, '__enter__'):
1329 self.__subproc.__enter__()
1330 return self
1332 def __exit__(self, *args, **kwargs):
1333 if hasattr(self.__subproc, '__exit__'):
1334 return self.__subproc.__exit__(*args, **kwargs)
1335 else:
1336 if self.stdout:
1337 self.stdout.close()
1338 if self.stderr:
1339 self.stderr.close()
1340 try:
1341 # Flushing a BufferedWriter may raise an error.
1342 if self.stdin:
1343 self.stdin.close()
1344 finally:
1345 # Wait for the process to terminate, to avoid zombies.
1346 self.wait()
1348 def __getattribute__(self, name):
1349 try:
1350 return object.__getattribute__(self, name)
1351 except AttributeError:
1352 try:
1353 return object.__getattribute__(self.__subproc, name)
1354 except AttributeError:
1355 raise AttributeError("%s instance has no attribute '%s'"
1356 % (self.__class__.__name__, name))
1358 def wait(self, timeout=None):
1359 if self.__subproc.returncode is not None:
1360 return self.__subproc.returncode
1361 ret = super(Popen, self).wait(timeout)
1362 self.__subproc.returncode = ret
1363 return ret
1366# =====================================================================
1367# --- system processes related functions
1368# =====================================================================
1371def pids():
1372 """Return a list of current running PIDs."""
1373 global _LOWEST_PID
1374 ret = sorted(_psplatform.pids())
1375 _LOWEST_PID = ret[0]
1376 return ret
1379def pid_exists(pid):
1380 """Return True if given PID exists in the current process list.
1381 This is faster than doing "pid in psutil.pids()" and
1382 should be preferred.
1383 """
1384 if pid < 0:
1385 return False
1386 elif pid == 0 and POSIX:
1387 # On POSIX we use os.kill() to determine PID existence.
1388 # According to "man 2 kill" PID 0 has a special meaning
1389 # though: it refers to <<every process in the process
1390 # group of the calling process>> and that is not we want
1391 # to do here.
1392 return pid in pids()
1393 else:
1394 return _psplatform.pid_exists(pid)
1397_pmap = {}
1400def process_iter(attrs=None, ad_value=None):
1401 """Return a generator yielding a Process instance for all
1402 running processes.
1404 Every new Process instance is only created once and then cached
1405 into an internal table which is updated every time this is used.
1407 Cached Process instances are checked for identity so that you're
1408 safe in case a PID has been reused by another process, in which
1409 case the cached instance is updated.
1411 The sorting order in which processes are yielded is based on
1412 their PIDs.
1414 *attrs* and *ad_value* have the same meaning as in
1415 Process.as_dict(). If *attrs* is specified as_dict() is called
1416 and the resulting dict is stored as a 'info' attribute attached
1417 to returned Process instance.
1418 If *attrs* is an empty list it will retrieve all process info
1419 (slow).
1420 """
1421 global _pmap
1423 def add(pid):
1424 proc = Process(pid)
1425 if attrs is not None:
1426 proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
1427 pmap[proc.pid] = proc
1428 return proc
1430 def remove(pid):
1431 pmap.pop(pid, None)
1433 pmap = _pmap.copy()
1434 a = set(pids())
1435 b = set(pmap.keys())
1436 new_pids = a - b
1437 gone_pids = b - a
1438 for pid in gone_pids:
1439 remove(pid)
1440 try:
1441 ls = sorted(list(pmap.items()) + list(dict.fromkeys(new_pids).items()))
1442 for pid, proc in ls:
1443 try:
1444 if proc is None: # new process
1445 yield add(pid)
1446 else:
1447 # use is_running() to check whether PID has been
1448 # reused by another process in which case yield a
1449 # new Process instance
1450 if proc.is_running():
1451 if attrs is not None:
1452 proc.info = proc.as_dict(
1453 attrs=attrs, ad_value=ad_value)
1454 yield proc
1455 else:
1456 yield add(pid)
1457 except NoSuchProcess:
1458 remove(pid)
1459 except AccessDenied:
1460 # Process creation time can't be determined hence there's
1461 # no way to tell whether the pid of the cached process
1462 # has been reused. Just return the cached version.
1463 if proc is None and pid in pmap:
1464 try:
1465 yield pmap[pid]
1466 except KeyError:
1467 # If we get here it is likely that 2 threads were
1468 # using process_iter().
1469 pass
1470 else:
1471 raise
1472 finally:
1473 _pmap = pmap
1476def wait_procs(procs, timeout=None, callback=None):
1477 """Convenience function which waits for a list of processes to
1478 terminate.
1480 Return a (gone, alive) tuple indicating which processes
1481 are gone and which ones are still alive.
1483 The gone ones will have a new *returncode* attribute indicating
1484 process exit status (may be None).
1486 *callback* is a function which gets called every time a process
1487 terminates (a Process instance is passed as callback argument).
1489 Function will return as soon as all processes terminate or when
1490 *timeout* occurs.
1491 Differently from Process.wait() it will not raise TimeoutExpired if
1492 *timeout* occurs.
1494 Typical use case is:
1496 - send SIGTERM to a list of processes
1497 - give them some time to terminate
1498 - send SIGKILL to those ones which are still alive
1500 Example:
1502 >>> def on_terminate(proc):
1503 ... print("process {} terminated".format(proc))
1504 ...
1505 >>> for p in procs:
1506 ... p.terminate()
1507 ...
1508 >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate)
1509 >>> for p in alive:
1510 ... p.kill()
1511 """
1512 def check_gone(proc, timeout):
1513 try:
1514 returncode = proc.wait(timeout=timeout)
1515 except TimeoutExpired:
1516 pass
1517 except _SubprocessTimeoutExpired:
1518 pass
1519 else:
1520 if returncode is not None or not proc.is_running():
1521 # Set new Process instance attribute.
1522 proc.returncode = returncode
1523 gone.add(proc)
1524 if callback is not None:
1525 callback(proc)
1527 if timeout is not None and not timeout >= 0:
1528 msg = "timeout must be a positive integer, got %s" % timeout
1529 raise ValueError(msg)
1530 gone = set()
1531 alive = set(procs)
1532 if callback is not None and not callable(callback):
1533 raise TypeError("callback %r is not a callable" % callable)
1534 if timeout is not None:
1535 deadline = _timer() + timeout
1537 while alive:
1538 if timeout is not None and timeout <= 0:
1539 break
1540 for proc in alive:
1541 # Make sure that every complete iteration (all processes)
1542 # will last max 1 sec.
1543 # We do this because we don't want to wait too long on a
1544 # single process: in case it terminates too late other
1545 # processes may disappear in the meantime and their PID
1546 # reused.
1547 max_timeout = 1.0 / len(alive)
1548 if timeout is not None:
1549 timeout = min((deadline - _timer()), max_timeout)
1550 if timeout <= 0:
1551 break
1552 check_gone(proc, timeout)
1553 else:
1554 check_gone(proc, max_timeout)
1555 alive = alive - gone
1557 if alive:
1558 # Last attempt over processes survived so far.
1559 # timeout == 0 won't make this function wait any further.
1560 for proc in alive:
1561 check_gone(proc, 0)
1562 alive = alive - gone
1564 return (list(gone), list(alive))
1567# =====================================================================
1568# --- CPU related functions
1569# =====================================================================
1572def cpu_count(logical=True):
1573 """Return the number of logical CPUs in the system (same as
1574 os.cpu_count() in Python 3.4).
1576 If *logical* is False return the number of physical cores only
1577 (e.g. hyper thread CPUs are excluded).
1579 Return None if undetermined.
1581 The return value is cached after first call.
1582 If desired cache can be cleared like this:
1584 >>> psutil.cpu_count.cache_clear()
1585 """
1586 if logical:
1587 ret = _psplatform.cpu_count_logical()
1588 else:
1589 ret = _psplatform.cpu_count_cores()
1590 if ret is not None and ret < 1:
1591 ret = None
1592 return ret
1595def cpu_times(percpu=False):
1596 """Return system-wide CPU times as a namedtuple.
1597 Every CPU time represents the seconds the CPU has spent in the
1598 given mode. The namedtuple's fields availability varies depending on the
1599 platform:
1601 - user
1602 - system
1603 - idle
1604 - nice (UNIX)
1605 - iowait (Linux)
1606 - irq (Linux, FreeBSD)
1607 - softirq (Linux)
1608 - steal (Linux >= 2.6.11)
1609 - guest (Linux >= 2.6.24)
1610 - guest_nice (Linux >= 3.2.0)
1612 When *percpu* is True return a list of namedtuples for each CPU.
1613 First element of the list refers to first CPU, second element
1614 to second CPU and so on.
1615 The order of the list is consistent across calls.
1616 """
1617 if not percpu:
1618 return _psplatform.cpu_times()
1619 else:
1620 return _psplatform.per_cpu_times()
1623try:
1624 _last_cpu_times = cpu_times()
1625except Exception:
1626 # Don't want to crash at import time.
1627 _last_cpu_times = None
1629try:
1630 _last_per_cpu_times = cpu_times(percpu=True)
1631except Exception:
1632 # Don't want to crash at import time.
1633 _last_per_cpu_times = None
1636def _cpu_tot_time(times):
1637 """Given a cpu_time() ntuple calculates the total CPU time
1638 (including idle time).
1639 """
1640 tot = sum(times)
1641 if LINUX:
1642 # On Linux guest times are already accounted in "user" or
1643 # "nice" times, so we subtract them from total.
1644 # Htop does the same. References:
1645 # https://github.com/giampaolo/psutil/pull/940
1646 # http://unix.stackexchange.com/questions/178045
1647 # https://github.com/torvalds/linux/blob/
1648 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/
1649 # cputime.c#L158
1650 tot -= getattr(times, "guest", 0) # Linux 2.6.24+
1651 tot -= getattr(times, "guest_nice", 0) # Linux 3.2.0+
1652 return tot
1655def _cpu_busy_time(times):
1656 """Given a cpu_time() ntuple calculates the busy CPU time.
1657 We do so by subtracting all idle CPU times.
1658 """
1659 busy = _cpu_tot_time(times)
1660 busy -= times.idle
1661 # Linux: "iowait" is time during which the CPU does not do anything
1662 # (waits for IO to complete). On Linux IO wait is *not* accounted
1663 # in "idle" time so we subtract it. Htop does the same.
1664 # References:
1665 # https://github.com/torvalds/linux/blob/
1666 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244
1667 busy -= getattr(times, "iowait", 0)
1668 return busy
1671def _cpu_times_deltas(t1, t2):
1672 assert t1._fields == t2._fields, (t1, t2)
1673 field_deltas = []
1674 for field in _psplatform.scputimes._fields:
1675 field_delta = getattr(t2, field) - getattr(t1, field)
1676 # CPU times are always supposed to increase over time
1677 # or at least remain the same and that's because time
1678 # cannot go backwards.
1679 # Surprisingly sometimes this might not be the case (at
1680 # least on Windows and Linux), see:
1681 # https://github.com/giampaolo/psutil/issues/392
1682 # https://github.com/giampaolo/psutil/issues/645
1683 # https://github.com/giampaolo/psutil/issues/1210
1684 # Trim negative deltas to zero to ignore decreasing fields.
1685 # top does the same. Reference:
1686 # https://gitlab.com/procps-ng/procps/blob/v3.3.12/top/top.c#L5063
1687 field_delta = max(0, field_delta)
1688 field_deltas.append(field_delta)
1689 return _psplatform.scputimes(*field_deltas)
1692def cpu_percent(interval=None, percpu=False):
1693 """Return a float representing the current system-wide CPU
1694 utilization as a percentage.
1696 When *interval* is > 0.0 compares system CPU times elapsed before
1697 and after the interval (blocking).
1699 When *interval* is 0.0 or None compares system CPU times elapsed
1700 since last call or module import, returning immediately (non
1701 blocking). That means the first time this is called it will
1702 return a meaningless 0.0 value which you should ignore.
1703 In this case is recommended for accuracy that this function be
1704 called with at least 0.1 seconds between calls.
1706 When *percpu* is True returns a list of floats representing the
1707 utilization as a percentage for each CPU.
1708 First element of the list refers to first CPU, second element
1709 to second CPU and so on.
1710 The order of the list is consistent across calls.
1712 Examples:
1714 >>> # blocking, system-wide
1715 >>> psutil.cpu_percent(interval=1)
1716 2.0
1717 >>>
1718 >>> # blocking, per-cpu
1719 >>> psutil.cpu_percent(interval=1, percpu=True)
1720 [2.0, 1.0]
1721 >>>
1722 >>> # non-blocking (percentage since last call)
1723 >>> psutil.cpu_percent(interval=None)
1724 2.9
1725 >>>
1726 """
1727 global _last_cpu_times
1728 global _last_per_cpu_times
1729 blocking = interval is not None and interval > 0.0
1730 if interval is not None and interval < 0:
1731 raise ValueError("interval is not positive (got %r)" % interval)
1733 def calculate(t1, t2):
1734 times_delta = _cpu_times_deltas(t1, t2)
1735 all_delta = _cpu_tot_time(times_delta)
1736 busy_delta = _cpu_busy_time(times_delta)
1738 try:
1739 busy_perc = (busy_delta / all_delta) * 100
1740 except ZeroDivisionError:
1741 return 0.0
1742 else:
1743 return round(busy_perc, 1)
1745 # system-wide usage
1746 if not percpu:
1747 if blocking:
1748 t1 = cpu_times()
1749 time.sleep(interval)
1750 else:
1751 t1 = _last_cpu_times
1752 if t1 is None:
1753 # Something bad happened at import time. We'll
1754 # get a meaningful result on the next call. See:
1755 # https://github.com/giampaolo/psutil/pull/715
1756 t1 = cpu_times()
1757 _last_cpu_times = cpu_times()
1758 return calculate(t1, _last_cpu_times)
1759 # per-cpu usage
1760 else:
1761 ret = []
1762 if blocking:
1763 tot1 = cpu_times(percpu=True)
1764 time.sleep(interval)
1765 else:
1766 tot1 = _last_per_cpu_times
1767 if tot1 is None:
1768 # Something bad happened at import time. We'll
1769 # get a meaningful result on the next call. See:
1770 # https://github.com/giampaolo/psutil/pull/715
1771 tot1 = cpu_times(percpu=True)
1772 _last_per_cpu_times = cpu_times(percpu=True)
1773 for t1, t2 in zip(tot1, _last_per_cpu_times):
1774 ret.append(calculate(t1, t2))
1775 return ret
1778# Use separate global vars for cpu_times_percent() so that it's
1779# independent from cpu_percent() and they can both be used within
1780# the same program.
1781_last_cpu_times_2 = _last_cpu_times
1782_last_per_cpu_times_2 = _last_per_cpu_times
1785def cpu_times_percent(interval=None, percpu=False):
1786 """Same as cpu_percent() but provides utilization percentages
1787 for each specific CPU time as is returned by cpu_times().
1788 For instance, on Linux we'll get:
1790 >>> cpu_times_percent()
1791 cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0,
1792 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
1793 >>>
1795 *interval* and *percpu* arguments have the same meaning as in
1796 cpu_percent().
1797 """
1798 global _last_cpu_times_2
1799 global _last_per_cpu_times_2
1800 blocking = interval is not None and interval > 0.0
1801 if interval is not None and interval < 0:
1802 raise ValueError("interval is not positive (got %r)" % interval)
1804 def calculate(t1, t2):
1805 nums = []
1806 times_delta = _cpu_times_deltas(t1, t2)
1807 all_delta = _cpu_tot_time(times_delta)
1808 # "scale" is the value to multiply each delta with to get percentages.
1809 # We use "max" to avoid division by zero (if all_delta is 0, then all
1810 # fields are 0 so percentages will be 0 too. all_delta cannot be a
1811 # fraction because cpu times are integers)
1812 scale = 100.0 / max(1, all_delta)
1813 for field_delta in times_delta:
1814 field_perc = field_delta * scale
1815 field_perc = round(field_perc, 1)
1816 # make sure we don't return negative values or values over 100%
1817 field_perc = min(max(0.0, field_perc), 100.0)
1818 nums.append(field_perc)
1819 return _psplatform.scputimes(*nums)
1821 # system-wide usage
1822 if not percpu:
1823 if blocking:
1824 t1 = cpu_times()
1825 time.sleep(interval)
1826 else:
1827 t1 = _last_cpu_times_2
1828 if t1 is None:
1829 # Something bad happened at import time. We'll
1830 # get a meaningful result on the next call. See:
1831 # https://github.com/giampaolo/psutil/pull/715
1832 t1 = cpu_times()
1833 _last_cpu_times_2 = cpu_times()
1834 return calculate(t1, _last_cpu_times_2)
1835 # per-cpu usage
1836 else:
1837 ret = []
1838 if blocking:
1839 tot1 = cpu_times(percpu=True)
1840 time.sleep(interval)
1841 else:
1842 tot1 = _last_per_cpu_times_2
1843 if tot1 is None:
1844 # Something bad happened at import time. We'll
1845 # get a meaningful result on the next call. See:
1846 # https://github.com/giampaolo/psutil/pull/715
1847 tot1 = cpu_times(percpu=True)
1848 _last_per_cpu_times_2 = cpu_times(percpu=True)
1849 for t1, t2 in zip(tot1, _last_per_cpu_times_2):
1850 ret.append(calculate(t1, t2))
1851 return ret
1854def cpu_stats():
1855 """Return CPU statistics."""
1856 return _psplatform.cpu_stats()
1859if hasattr(_psplatform, "cpu_freq"):
1861 def cpu_freq(percpu=False):
1862 """Return CPU frequency as a namedtuple including current,
1863 min and max frequency expressed in Mhz.
1865 If *percpu* is True and the system supports per-cpu frequency
1866 retrieval (Linux only) a list of frequencies is returned for
1867 each CPU. If not a list with one element is returned.
1868 """
1869 ret = _psplatform.cpu_freq()
1870 if percpu:
1871 return ret
1872 else:
1873 num_cpus = float(len(ret))
1874 if num_cpus == 0:
1875 return None
1876 elif num_cpus == 1:
1877 return ret[0]
1878 else:
1879 currs, mins, maxs = 0.0, 0.0, 0.0
1880 set_none = False
1881 for cpu in ret:
1882 currs += cpu.current
1883 # On Linux if /proc/cpuinfo is used min/max are set
1884 # to None.
1885 if LINUX and cpu.min is None:
1886 set_none = True
1887 continue
1888 mins += cpu.min
1889 maxs += cpu.max
1891 current = currs / num_cpus
1893 if set_none:
1894 min_ = max_ = None
1895 else:
1896 min_ = mins / num_cpus
1897 max_ = maxs / num_cpus
1899 return _common.scpufreq(current, min_, max_)
1901 __all__.append("cpu_freq")
1904if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"):
1905 # Perform this hasattr check once on import time to either use the
1906 # platform based code or proxy straight from the os module.
1907 if hasattr(os, "getloadavg"):
1908 getloadavg = os.getloadavg
1909 else:
1910 getloadavg = _psplatform.getloadavg
1912 __all__.append("getloadavg")
1915# =====================================================================
1916# --- system memory related functions
1917# =====================================================================
1920def virtual_memory():
1921 """Return statistics about system memory usage as a namedtuple
1922 including the following fields, expressed in bytes:
1924 - total:
1925 total physical memory available.
1927 - available:
1928 the memory that can be given instantly to processes without the
1929 system going into swap.
1930 This is calculated by summing different memory values depending
1931 on the platform and it is supposed to be used to monitor actual
1932 memory usage in a cross platform fashion.
1934 - percent:
1935 the percentage usage calculated as (total - available) / total * 100
1937 - used:
1938 memory used, calculated differently depending on the platform and
1939 designed for informational purposes only:
1940 macOS: active + wired
1941 BSD: active + wired + cached
1942 Linux: total - free
1944 - free:
1945 memory not being used at all (zeroed) that is readily available;
1946 note that this doesn't reflect the actual memory available
1947 (use 'available' instead)
1949 Platform-specific fields:
1951 - active (UNIX):
1952 memory currently in use or very recently used, and so it is in RAM.
1954 - inactive (UNIX):
1955 memory that is marked as not used.
1957 - buffers (BSD, Linux):
1958 cache for things like file system metadata.
1960 - cached (BSD, macOS):
1961 cache for various things.
1963 - wired (macOS, BSD):
1964 memory that is marked to always stay in RAM. It is never moved to disk.
1966 - shared (BSD):
1967 memory that may be simultaneously accessed by multiple processes.
1969 The sum of 'used' and 'available' does not necessarily equal total.
1970 On Windows 'available' and 'free' are the same.
1971 """
1972 global _TOTAL_PHYMEM
1973 ret = _psplatform.virtual_memory()
1974 # cached for later use in Process.memory_percent()
1975 _TOTAL_PHYMEM = ret.total
1976 return ret
1979def swap_memory():
1980 """Return system swap memory statistics as a namedtuple including
1981 the following fields:
1983 - total: total swap memory in bytes
1984 - used: used swap memory in bytes
1985 - free: free swap memory in bytes
1986 - percent: the percentage usage
1987 - sin: no. of bytes the system has swapped in from disk (cumulative)
1988 - sout: no. of bytes the system has swapped out from disk (cumulative)
1990 'sin' and 'sout' on Windows are meaningless and always set to 0.
1991 """
1992 return _psplatform.swap_memory()
1995# =====================================================================
1996# --- disks/paritions related functions
1997# =====================================================================
2000def disk_usage(path):
2001 """Return disk usage statistics about the given *path* as a
2002 namedtuple including total, used and free space expressed in bytes
2003 plus the percentage usage.
2004 """
2005 return _psplatform.disk_usage(path)
2008def disk_partitions(all=False):
2009 """Return mounted partitions as a list of
2010 (device, mountpoint, fstype, opts) namedtuple.
2011 'opts' field is a raw string separated by commas indicating mount
2012 options which may vary depending on the platform.
2014 If *all* parameter is False return physical devices only and ignore
2015 all others.
2016 """
2017 def pathconf(path, name):
2018 try:
2019 return os.pathconf(path, name)
2020 except (OSError, AttributeError):
2021 pass
2023 ret = _psplatform.disk_partitions(all)
2024 if POSIX:
2025 new = []
2026 for item in ret:
2027 nt = item._replace(
2028 maxfile=pathconf(item.mountpoint, 'PC_NAME_MAX'),
2029 maxpath=pathconf(item.mountpoint, 'PC_PATH_MAX'))
2030 new.append(nt)
2031 return new
2032 else:
2033 return ret
2036def disk_io_counters(perdisk=False, nowrap=True):
2037 """Return system disk I/O statistics as a namedtuple including
2038 the following fields:
2040 - read_count: number of reads
2041 - write_count: number of writes
2042 - read_bytes: number of bytes read
2043 - write_bytes: number of bytes written
2044 - read_time: time spent reading from disk (in ms)
2045 - write_time: time spent writing to disk (in ms)
2047 Platform specific:
2049 - busy_time: (Linux, FreeBSD) time spent doing actual I/Os (in ms)
2050 - read_merged_count (Linux): number of merged reads
2051 - write_merged_count (Linux): number of merged writes
2053 If *perdisk* is True return the same information for every
2054 physical disk installed on the system as a dictionary
2055 with partition names as the keys and the namedtuple
2056 described above as the values.
2058 If *nowrap* is True it detects and adjust the numbers which overflow
2059 and wrap (restart from 0) and add "old value" to "new value" so that
2060 the returned numbers will always be increasing or remain the same,
2061 but never decrease.
2062 "disk_io_counters.cache_clear()" can be used to invalidate the
2063 cache.
2065 On recent Windows versions 'diskperf -y' command may need to be
2066 executed first otherwise this function won't find any disk.
2067 """
2068 kwargs = dict(perdisk=perdisk) if LINUX else {}
2069 rawdict = _psplatform.disk_io_counters(**kwargs)
2070 if not rawdict:
2071 return {} if perdisk else None
2072 if nowrap:
2073 rawdict = _wrap_numbers(rawdict, 'psutil.disk_io_counters')
2074 nt = getattr(_psplatform, "sdiskio", _common.sdiskio)
2075 if perdisk:
2076 for disk, fields in rawdict.items():
2077 rawdict[disk] = nt(*fields)
2078 return rawdict
2079 else:
2080 return nt(*(sum(x) for x in zip(*rawdict.values())))
2083disk_io_counters.cache_clear = functools.partial(
2084 _wrap_numbers.cache_clear, 'psutil.disk_io_counters')
2085disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2088# =====================================================================
2089# --- network related functions
2090# =====================================================================
2093def net_io_counters(pernic=False, nowrap=True):
2094 """Return network I/O statistics as a namedtuple including
2095 the following fields:
2097 - bytes_sent: number of bytes sent
2098 - bytes_recv: number of bytes received
2099 - packets_sent: number of packets sent
2100 - packets_recv: number of packets received
2101 - errin: total number of errors while receiving
2102 - errout: total number of errors while sending
2103 - dropin: total number of incoming packets which were dropped
2104 - dropout: total number of outgoing packets which were dropped
2105 (always 0 on macOS and BSD)
2107 If *pernic* is True return the same information for every
2108 network interface installed on the system as a dictionary
2109 with network interface names as the keys and the namedtuple
2110 described above as the values.
2112 If *nowrap* is True it detects and adjust the numbers which overflow
2113 and wrap (restart from 0) and add "old value" to "new value" so that
2114 the returned numbers will always be increasing or remain the same,
2115 but never decrease.
2116 "disk_io_counters.cache_clear()" can be used to invalidate the
2117 cache.
2118 """
2119 rawdict = _psplatform.net_io_counters()
2120 if not rawdict:
2121 return {} if pernic else None
2122 if nowrap:
2123 rawdict = _wrap_numbers(rawdict, 'psutil.net_io_counters')
2124 if pernic:
2125 for nic, fields in rawdict.items():
2126 rawdict[nic] = _common.snetio(*fields)
2127 return rawdict
2128 else:
2129 return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
2132net_io_counters.cache_clear = functools.partial(
2133 _wrap_numbers.cache_clear, 'psutil.net_io_counters')
2134net_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2137def net_connections(kind='inet'):
2138 """Return system-wide socket connections as a list of
2139 (fd, family, type, laddr, raddr, status, pid) namedtuples.
2140 In case of limited privileges 'fd' and 'pid' may be set to -1
2141 and None respectively.
2142 The *kind* parameter filters for connections that fit the
2143 following criteria:
2145 +------------+----------------------------------------------------+
2146 | Kind Value | Connections using |
2147 +------------+----------------------------------------------------+
2148 | inet | IPv4 and IPv6 |
2149 | inet4 | IPv4 |
2150 | inet6 | IPv6 |
2151 | tcp | TCP |
2152 | tcp4 | TCP over IPv4 |
2153 | tcp6 | TCP over IPv6 |
2154 | udp | UDP |
2155 | udp4 | UDP over IPv4 |
2156 | udp6 | UDP over IPv6 |
2157 | unix | UNIX socket (both UDP and TCP protocols) |
2158 | all | the sum of all the possible families and protocols |
2159 +------------+----------------------------------------------------+
2161 On macOS this function requires root privileges.
2162 """
2163 return _psplatform.net_connections(kind)
2166def net_if_addrs():
2167 """Return the addresses associated to each NIC (network interface
2168 card) installed on the system as a dictionary whose keys are the
2169 NIC names and value is a list of namedtuples for each address
2170 assigned to the NIC. Each namedtuple includes 5 fields:
2172 - family: can be either socket.AF_INET, socket.AF_INET6 or
2173 psutil.AF_LINK, which refers to a MAC address.
2174 - address: is the primary address and it is always set.
2175 - netmask: and 'broadcast' and 'ptp' may be None.
2176 - ptp: stands for "point to point" and references the
2177 destination address on a point to point interface
2178 (typically a VPN).
2179 - broadcast: and *ptp* are mutually exclusive.
2181 Note: you can have more than one address of the same family
2182 associated with each interface.
2183 """
2184 has_enums = sys.version_info >= (3, 4)
2185 if has_enums:
2186 import socket
2187 rawlist = _psplatform.net_if_addrs()
2188 rawlist.sort(key=lambda x: x[1]) # sort by family
2189 ret = collections.defaultdict(list)
2190 for name, fam, addr, mask, broadcast, ptp in rawlist:
2191 if has_enums:
2192 try:
2193 fam = socket.AddressFamily(fam)
2194 except ValueError:
2195 if WINDOWS and fam == -1:
2196 fam = _psplatform.AF_LINK
2197 elif (hasattr(_psplatform, "AF_LINK") and
2198 _psplatform.AF_LINK == fam):
2199 # Linux defines AF_LINK as an alias for AF_PACKET.
2200 # We re-set the family here so that repr(family)
2201 # will show AF_LINK rather than AF_PACKET
2202 fam = _psplatform.AF_LINK
2203 if fam == _psplatform.AF_LINK:
2204 # The underlying C function may return an incomplete MAC
2205 # address in which case we fill it with null bytes, see:
2206 # https://github.com/giampaolo/psutil/issues/786
2207 separator = ":" if POSIX else "-"
2208 while addr.count(separator) < 5:
2209 addr += "%s00" % separator
2210 ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp))
2211 return dict(ret)
2214def net_if_stats():
2215 """Return information about each NIC (network interface card)
2216 installed on the system as a dictionary whose keys are the
2217 NIC names and value is a namedtuple with the following fields:
2219 - isup: whether the interface is up (bool)
2220 - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or
2221 NIC_DUPLEX_UNKNOWN
2222 - speed: the NIC speed expressed in mega bits (MB); if it can't
2223 be determined (e.g. 'localhost') it will be set to 0.
2224 - mtu: the maximum transmission unit expressed in bytes.
2225 """
2226 return _psplatform.net_if_stats()
2229# =====================================================================
2230# --- sensors
2231# =====================================================================
2234# Linux, macOS
2235if hasattr(_psplatform, "sensors_temperatures"):
2237 def sensors_temperatures(fahrenheit=False):
2238 """Return hardware temperatures. Each entry is a namedtuple
2239 representing a certain hardware sensor (it may be a CPU, an
2240 hard disk or something else, depending on the OS and its
2241 configuration).
2242 All temperatures are expressed in celsius unless *fahrenheit*
2243 is set to True.
2244 """
2245 def convert(n):
2246 if n is not None:
2247 return (float(n) * 9 / 5) + 32 if fahrenheit else n
2249 ret = collections.defaultdict(list)
2250 rawdict = _psplatform.sensors_temperatures()
2252 for name, values in rawdict.items():
2253 while values:
2254 label, current, high, critical = values.pop(0)
2255 current = convert(current)
2256 high = convert(high)
2257 critical = convert(critical)
2259 if high and not critical:
2260 critical = high
2261 elif critical and not high:
2262 high = critical
2264 ret[name].append(
2265 _common.shwtemp(label, current, high, critical))
2267 return dict(ret)
2269 __all__.append("sensors_temperatures")
2272# Linux
2273if hasattr(_psplatform, "sensors_fans"):
2275 def sensors_fans():
2276 """Return fans speed. Each entry is a namedtuple
2277 representing a certain hardware sensor.
2278 All speed are expressed in RPM (rounds per minute).
2279 """
2280 return _psplatform.sensors_fans()
2282 __all__.append("sensors_fans")
2285# Linux, Windows, FreeBSD, macOS
2286if hasattr(_psplatform, "sensors_battery"):
2288 def sensors_battery():
2289 """Return battery information. If no battery is installed
2290 returns None.
2292 - percent: battery power left as a percentage.
2293 - secsleft: a rough approximation of how many seconds are left
2294 before the battery runs out of power. May be
2295 POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED.
2296 - power_plugged: True if the AC power cable is connected.
2297 """
2298 return _psplatform.sensors_battery()
2300 __all__.append("sensors_battery")
2303# =====================================================================
2304# --- other system related functions
2305# =====================================================================
2308def boot_time():
2309 """Return the system boot time expressed in seconds since the epoch."""
2310 # Note: we are not caching this because it is subject to
2311 # system clock updates.
2312 return _psplatform.boot_time()
2315def users():
2316 """Return users currently connected on the system as a list of
2317 namedtuples including the following fields.
2319 - user: the name of the user
2320 - terminal: the tty or pseudo-tty associated with the user, if any.
2321 - host: the host name associated with the entry, if any.
2322 - started: the creation time as a floating point number expressed in
2323 seconds since the epoch.
2324 """
2325 return _psplatform.users()
2328# =====================================================================
2329# --- Windows services
2330# =====================================================================
2333if WINDOWS:
2335 def win_service_iter():
2336 """Return a generator yielding a WindowsService instance for all
2337 Windows services installed.
2338 """
2339 return _psplatform.win_service_iter()
2341 def win_service_get(name):
2342 """Get a Windows service by *name*.
2343 Raise NoSuchProcess if no service with such name exists.
2344 """
2345 return _psplatform.win_service_get(name)
2348# =====================================================================
2351def _set_debug(value):
2352 """Enable or disable PSUTIL_DEBUG option, which prints debugging
2353 messages to stderr.
2354 """
2355 import psutil._common
2356 psutil._common.PSUTIL_DEBUG = bool(value)
2357 _psplatform.cext.set_debug(bool(value))
2360def test(): # pragma: no cover
2361 from ._common import bytes2human
2362 from ._compat import get_terminal_size
2364 today_day = datetime.date.today()
2365 templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s %s"
2366 attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times',
2367 'create_time', 'memory_info', 'status', 'nice', 'username']
2368 print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE", # NOQA
2369 "STATUS", "START", "TIME", "CMDLINE"))
2370 for p in process_iter(attrs, ad_value=None):
2371 if p.info['create_time']:
2372 ctime = datetime.datetime.fromtimestamp(p.info['create_time'])
2373 if ctime.date() == today_day:
2374 ctime = ctime.strftime("%H:%M")
2375 else:
2376 ctime = ctime.strftime("%b%d")
2377 else:
2378 ctime = ''
2379 if p.info['cpu_times']:
2380 cputime = time.strftime("%M:%S",
2381 time.localtime(sum(p.info['cpu_times'])))
2382 else:
2383 cputime = ''
2385 user = p.info['username'] or ''
2386 if not user and POSIX:
2387 try:
2388 user = p.uids()[0]
2389 except Error:
2390 pass
2391 if user and WINDOWS and '\\' in user:
2392 user = user.split('\\')[1]
2393 user = user[:9]
2394 vms = bytes2human(p.info['memory_info'].vms) if \
2395 p.info['memory_info'] is not None else ''
2396 rss = bytes2human(p.info['memory_info'].rss) if \
2397 p.info['memory_info'] is not None else ''
2398 memp = round(p.info['memory_percent'], 1) if \
2399 p.info['memory_percent'] is not None else ''
2400 nice = int(p.info['nice']) if p.info['nice'] else ''
2401 if p.info['cmdline']:
2402 cmdline = ' '.join(p.info['cmdline'])
2403 else:
2404 cmdline = p.info['name']
2405 status = p.info['status'][:5] if p.info['status'] else ''
2407 line = templ % (
2408 user[:10],
2409 p.info['pid'],
2410 memp,
2411 vms,
2412 rss,
2413 nice,
2414 status,
2415 ctime,
2416 cputime,
2417 cmdline)
2418 print(line[:get_terminal_size()[0]]) # NOQA
2421del memoize_when_activated, division
2422if sys.version_info[0] < 3:
2423 del num, x
2425if __name__ == "__main__":
2426 test()