Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/psutil/__init__.py: 26%
943 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +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.4"
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 = dict()
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:
630 pass
631 else:
632 if cmdline:
633 extended_name = os.path.basename(cmdline[0])
634 if extended_name.startswith(name):
635 name = extended_name
636 self._name = name
637 self._proc._name = name
638 return name
640 def exe(self):
641 """The process executable as an absolute path.
642 May also be an empty string.
643 The return value is cached after first call.
644 """
645 def guess_it(fallback):
646 # try to guess exe from cmdline[0] in absence of a native
647 # exe representation
648 cmdline = self.cmdline()
649 if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
650 exe = cmdline[0] # the possible exe
651 # Attempt to guess only in case of an absolute path.
652 # It is not safe otherwise as the process might have
653 # changed cwd.
654 if (os.path.isabs(exe) and
655 os.path.isfile(exe) and
656 os.access(exe, os.X_OK)):
657 return exe
658 if isinstance(fallback, AccessDenied):
659 raise fallback
660 return fallback
662 if self._exe is None:
663 try:
664 exe = self._proc.exe()
665 except AccessDenied as err:
666 return guess_it(fallback=err)
667 else:
668 if not exe:
669 # underlying implementation can legitimately return an
670 # empty string; if that's the case we don't want to
671 # raise AD while guessing from the cmdline
672 try:
673 exe = guess_it(fallback=exe)
674 except AccessDenied:
675 pass
676 self._exe = exe
677 return self._exe
679 def cmdline(self):
680 """The command line this process has been called with."""
681 return self._proc.cmdline()
683 def status(self):
684 """The process current status as a STATUS_* constant."""
685 try:
686 return self._proc.status()
687 except ZombieProcess:
688 return STATUS_ZOMBIE
690 def username(self):
691 """The name of the user that owns the process.
692 On UNIX this is calculated by using *real* process uid.
693 """
694 if POSIX:
695 if pwd is None:
696 # might happen if python was installed from sources
697 raise ImportError(
698 "requires pwd module shipped with standard python")
699 real_uid = self.uids().real
700 try:
701 return pwd.getpwuid(real_uid).pw_name
702 except KeyError:
703 # the uid can't be resolved by the system
704 return str(real_uid)
705 else:
706 return self._proc.username()
708 def create_time(self):
709 """The process creation time as a floating point number
710 expressed in seconds since the epoch.
711 The return value is cached after first call.
712 """
713 if self._create_time is None:
714 self._create_time = self._proc.create_time()
715 return self._create_time
717 def cwd(self):
718 """Process current working directory as an absolute path."""
719 return self._proc.cwd()
721 def nice(self, value=None):
722 """Get or set process niceness (priority)."""
723 if value is None:
724 return self._proc.nice_get()
725 else:
726 if not self.is_running():
727 raise NoSuchProcess(self.pid, self._name)
728 self._proc.nice_set(value)
730 if POSIX:
732 @memoize_when_activated
733 def uids(self):
734 """Return process UIDs as a (real, effective, saved)
735 namedtuple.
736 """
737 return self._proc.uids()
739 def gids(self):
740 """Return process GIDs as a (real, effective, saved)
741 namedtuple.
742 """
743 return self._proc.gids()
745 def terminal(self):
746 """The terminal associated with this process, if any,
747 else None.
748 """
749 return self._proc.terminal()
751 def num_fds(self):
752 """Return the number of file descriptors opened by this
753 process (POSIX only).
754 """
755 return self._proc.num_fds()
757 # Linux, BSD, AIX and Windows only
758 if hasattr(_psplatform.Process, "io_counters"):
760 def io_counters(self):
761 """Return process I/O statistics as a
762 (read_count, write_count, read_bytes, write_bytes)
763 namedtuple.
764 Those are the number of read/write calls performed and the
765 amount of bytes read and written by the process.
766 """
767 return self._proc.io_counters()
769 # Linux and Windows
770 if hasattr(_psplatform.Process, "ionice_get"):
772 def ionice(self, ioclass=None, value=None):
773 """Get or set process I/O niceness (priority).
775 On Linux *ioclass* is one of the IOPRIO_CLASS_* constants.
776 *value* is a number which goes from 0 to 7. The higher the
777 value, the lower the I/O priority of the process.
779 On Windows only *ioclass* is used and it can be set to 2
780 (normal), 1 (low) or 0 (very low).
782 Available on Linux and Windows > Vista only.
783 """
784 if ioclass is None:
785 if value is not None:
786 raise ValueError("'ioclass' argument must be specified")
787 return self._proc.ionice_get()
788 else:
789 return self._proc.ionice_set(ioclass, value)
791 # Linux / FreeBSD only
792 if hasattr(_psplatform.Process, "rlimit"):
794 def rlimit(self, resource, limits=None):
795 """Get or set process resource limits as a (soft, hard)
796 tuple.
798 *resource* is one of the RLIMIT_* constants.
799 *limits* is supposed to be a (soft, hard) tuple.
801 See "man prlimit" for further info.
802 Available on Linux and FreeBSD only.
803 """
804 return self._proc.rlimit(resource, limits)
806 # Windows, Linux and FreeBSD only
807 if hasattr(_psplatform.Process, "cpu_affinity_get"):
809 def cpu_affinity(self, cpus=None):
810 """Get or set process CPU affinity.
811 If specified, *cpus* must be a list of CPUs for which you
812 want to set the affinity (e.g. [0, 1]).
813 If an empty list is passed, all egible CPUs are assumed
814 (and set).
815 (Windows, Linux and BSD only).
816 """
817 if cpus is None:
818 return sorted(set(self._proc.cpu_affinity_get()))
819 else:
820 if not cpus:
821 if hasattr(self._proc, "_get_eligible_cpus"):
822 cpus = self._proc._get_eligible_cpus()
823 else:
824 cpus = tuple(range(len(cpu_times(percpu=True))))
825 self._proc.cpu_affinity_set(list(set(cpus)))
827 # Linux, FreeBSD, SunOS
828 if hasattr(_psplatform.Process, "cpu_num"):
830 def cpu_num(self):
831 """Return what CPU this process is currently running on.
832 The returned number should be <= psutil.cpu_count()
833 and <= len(psutil.cpu_percent(percpu=True)).
834 It may be used in conjunction with
835 psutil.cpu_percent(percpu=True) to observe the system
836 workload distributed across CPUs.
837 """
838 return self._proc.cpu_num()
840 # All platforms has it, but maybe not in the future.
841 if hasattr(_psplatform.Process, "environ"):
843 def environ(self):
844 """The environment variables of the process as a dict. Note: this
845 might not reflect changes made after the process started. """
846 return self._proc.environ()
848 if WINDOWS:
850 def num_handles(self):
851 """Return the number of handles opened by this process
852 (Windows only).
853 """
854 return self._proc.num_handles()
856 def num_ctx_switches(self):
857 """Return the number of voluntary and involuntary context
858 switches performed by this process.
859 """
860 return self._proc.num_ctx_switches()
862 def num_threads(self):
863 """Return the number of threads used by this process."""
864 return self._proc.num_threads()
866 if hasattr(_psplatform.Process, "threads"):
868 def threads(self):
869 """Return threads opened by process as a list of
870 (id, user_time, system_time) namedtuples representing
871 thread id and thread CPU times (user/system).
872 On OpenBSD this method requires root access.
873 """
874 return self._proc.threads()
876 @_assert_pid_not_reused
877 def children(self, recursive=False):
878 """Return the children of this process as a list of Process
879 instances, pre-emptively checking whether PID has been reused.
880 If *recursive* is True return all the parent descendants.
882 Example (A == this process):
884 A ─┐
885 │
886 ├─ B (child) ─┐
887 │ └─ X (grandchild) ─┐
888 │ └─ Y (great grandchild)
889 ├─ C (child)
890 └─ D (child)
892 >>> import psutil
893 >>> p = psutil.Process()
894 >>> p.children()
895 B, C, D
896 >>> p.children(recursive=True)
897 B, X, Y, C, D
899 Note that in the example above if process X disappears
900 process Y won't be listed as the reference to process A
901 is lost.
902 """
903 ppid_map = _ppid_map()
904 ret = []
905 if not recursive:
906 for pid, ppid in ppid_map.items():
907 if ppid == self.pid:
908 try:
909 child = Process(pid)
910 # if child happens to be older than its parent
911 # (self) it means child's PID has been reused
912 if self.create_time() <= child.create_time():
913 ret.append(child)
914 except (NoSuchProcess, ZombieProcess):
915 pass
916 else:
917 # Construct a {pid: [child pids]} dict
918 reverse_ppid_map = collections.defaultdict(list)
919 for pid, ppid in ppid_map.items():
920 reverse_ppid_map[ppid].append(pid)
921 # Recursively traverse that dict, starting from self.pid,
922 # such that we only call Process() on actual children
923 seen = set()
924 stack = [self.pid]
925 while stack:
926 pid = stack.pop()
927 if pid in seen:
928 # Since pids can be reused while the ppid_map is
929 # constructed, there may be rare instances where
930 # there's a cycle in the recorded process "tree".
931 continue
932 seen.add(pid)
933 for child_pid in reverse_ppid_map[pid]:
934 try:
935 child = Process(child_pid)
936 # if child happens to be older than its parent
937 # (self) it means child's PID has been reused
938 intime = self.create_time() <= child.create_time()
939 if intime:
940 ret.append(child)
941 stack.append(child_pid)
942 except (NoSuchProcess, ZombieProcess):
943 pass
944 return ret
946 def cpu_percent(self, interval=None):
947 """Return a float representing the current process CPU
948 utilization as a percentage.
950 When *interval* is 0.0 or None (default) compares process times
951 to system CPU times elapsed since last call, returning
952 immediately (non-blocking). That means that the first time
953 this is called it will return a meaningful 0.0 value.
955 When *interval* is > 0.0 compares process times to system CPU
956 times elapsed before and after the interval (blocking).
958 In this case is recommended for accuracy that this function
959 be called with at least 0.1 seconds between calls.
961 A value > 100.0 can be returned in case of processes running
962 multiple threads on different CPU cores.
964 The returned value is explicitly NOT split evenly between
965 all available logical CPUs. This means that a busy loop process
966 running on a system with 2 logical CPUs will be reported as
967 having 100% CPU utilization instead of 50%.
969 Examples:
971 >>> import psutil
972 >>> p = psutil.Process(os.getpid())
973 >>> # blocking
974 >>> p.cpu_percent(interval=1)
975 2.0
976 >>> # non-blocking (percentage since last call)
977 >>> p.cpu_percent(interval=None)
978 2.9
979 >>>
980 """
981 blocking = interval is not None and interval > 0.0
982 if interval is not None and interval < 0:
983 raise ValueError("interval is not positive (got %r)" % interval)
984 num_cpus = cpu_count() or 1
986 def timer():
987 return _timer() * num_cpus
989 if blocking:
990 st1 = timer()
991 pt1 = self._proc.cpu_times()
992 time.sleep(interval)
993 st2 = timer()
994 pt2 = self._proc.cpu_times()
995 else:
996 st1 = self._last_sys_cpu_times
997 pt1 = self._last_proc_cpu_times
998 st2 = timer()
999 pt2 = self._proc.cpu_times()
1000 if st1 is None or pt1 is None:
1001 self._last_sys_cpu_times = st2
1002 self._last_proc_cpu_times = pt2
1003 return 0.0
1005 delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
1006 delta_time = st2 - st1
1007 # reset values for next call in case of interval == None
1008 self._last_sys_cpu_times = st2
1009 self._last_proc_cpu_times = pt2
1011 try:
1012 # This is the utilization split evenly between all CPUs.
1013 # E.g. a busy loop process on a 2-CPU-cores system at this
1014 # point is reported as 50% instead of 100%.
1015 overall_cpus_percent = ((delta_proc / delta_time) * 100)
1016 except ZeroDivisionError:
1017 # interval was too low
1018 return 0.0
1019 else:
1020 # Note 1:
1021 # in order to emulate "top" we multiply the value for the num
1022 # of CPU cores. This way the busy process will be reported as
1023 # having 100% (or more) usage.
1024 #
1025 # Note 2:
1026 # taskmgr.exe on Windows differs in that it will show 50%
1027 # instead.
1028 #
1029 # Note 3:
1030 # a percentage > 100 is legitimate as it can result from a
1031 # process with multiple threads running on different CPU
1032 # cores (top does the same), see:
1033 # http://stackoverflow.com/questions/1032357
1034 # https://github.com/giampaolo/psutil/issues/474
1035 single_cpu_percent = overall_cpus_percent * num_cpus
1036 return round(single_cpu_percent, 1)
1038 @memoize_when_activated
1039 def cpu_times(self):
1040 """Return a (user, system, children_user, children_system)
1041 namedtuple representing the accumulated process time, in
1042 seconds.
1043 This is similar to os.times() but per-process.
1044 On macOS and Windows children_user and children_system are
1045 always set to 0.
1046 """
1047 return self._proc.cpu_times()
1049 @memoize_when_activated
1050 def memory_info(self):
1051 """Return a namedtuple with variable fields depending on the
1052 platform, representing memory information about the process.
1054 The "portable" fields available on all platforms are `rss` and `vms`.
1056 All numbers are expressed in bytes.
1057 """
1058 return self._proc.memory_info()
1060 @_common.deprecated_method(replacement="memory_info")
1061 def memory_info_ex(self):
1062 return self.memory_info()
1064 def memory_full_info(self):
1065 """This method returns the same information as memory_info(),
1066 plus, on some platform (Linux, macOS, Windows), also provides
1067 additional metrics (USS, PSS and swap).
1068 The additional metrics provide a better representation of actual
1069 process memory usage.
1071 Namely USS is the memory which is unique to a process and which
1072 would be freed if the process was terminated right now.
1074 It does so by passing through the whole process address.
1075 As such it usually requires higher user privileges than
1076 memory_info() and is considerably slower.
1077 """
1078 return self._proc.memory_full_info()
1080 def memory_percent(self, memtype="rss"):
1081 """Compare process memory to total physical system memory and
1082 calculate process memory utilization as a percentage.
1083 *memtype* argument is a string that dictates what type of
1084 process memory you want to compare against (defaults to "rss").
1085 The list of available strings can be obtained like this:
1087 >>> psutil.Process().memory_info()._fields
1088 ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss')
1089 """
1090 valid_types = list(_psplatform.pfullmem._fields)
1091 if memtype not in valid_types:
1092 raise ValueError("invalid memtype %r; valid types are %r" % (
1093 memtype, tuple(valid_types)))
1094 fun = self.memory_info if memtype in _psplatform.pmem._fields else \
1095 self.memory_full_info
1096 metrics = fun()
1097 value = getattr(metrics, memtype)
1099 # use cached value if available
1100 total_phymem = _TOTAL_PHYMEM or virtual_memory().total
1101 if not total_phymem > 0:
1102 # we should never get here
1103 raise ValueError(
1104 "can't calculate process memory percent because "
1105 "total physical system memory is not positive (%r)"
1106 % total_phymem)
1107 return (value / float(total_phymem)) * 100
1109 if hasattr(_psplatform.Process, "memory_maps"):
1110 def memory_maps(self, grouped=True):
1111 """Return process' mapped memory regions as a list of namedtuples
1112 whose fields are variable depending on the platform.
1114 If *grouped* is True the mapped regions with the same 'path'
1115 are grouped together and the different memory fields are summed.
1117 If *grouped* is False every mapped region is shown as a single
1118 entity and the namedtuple will also include the mapped region's
1119 address space ('addr') and permission set ('perms').
1120 """
1121 it = self._proc.memory_maps()
1122 if grouped:
1123 d = {}
1124 for tupl in it:
1125 path = tupl[2]
1126 nums = tupl[3:]
1127 try:
1128 d[path] = map(lambda x, y: x + y, d[path], nums)
1129 except KeyError:
1130 d[path] = nums
1131 nt = _psplatform.pmmap_grouped
1132 return [nt(path, *d[path]) for path in d] # NOQA
1133 else:
1134 nt = _psplatform.pmmap_ext
1135 return [nt(*x) for x in it]
1137 def open_files(self):
1138 """Return files opened by process as a list of
1139 (path, fd) namedtuples including the absolute file name
1140 and file descriptor number.
1141 """
1142 return self._proc.open_files()
1144 def connections(self, kind='inet'):
1145 """Return socket connections opened by process as a list of
1146 (fd, family, type, laddr, raddr, status) namedtuples.
1147 The *kind* parameter filters for connections that match the
1148 following criteria:
1150 +------------+----------------------------------------------------+
1151 | Kind Value | Connections using |
1152 +------------+----------------------------------------------------+
1153 | inet | IPv4 and IPv6 |
1154 | inet4 | IPv4 |
1155 | inet6 | IPv6 |
1156 | tcp | TCP |
1157 | tcp4 | TCP over IPv4 |
1158 | tcp6 | TCP over IPv6 |
1159 | udp | UDP |
1160 | udp4 | UDP over IPv4 |
1161 | udp6 | UDP over IPv6 |
1162 | unix | UNIX socket (both UDP and TCP protocols) |
1163 | all | the sum of all the possible families and protocols |
1164 +------------+----------------------------------------------------+
1165 """
1166 return self._proc.connections(kind)
1168 # --- signals
1170 if POSIX:
1171 def _send_signal(self, sig):
1172 assert not self.pid < 0, self.pid
1173 if self.pid == 0:
1174 # see "man 2 kill"
1175 raise ValueError(
1176 "preventing sending signal to process with PID 0 as it "
1177 "would affect every process in the process group of the "
1178 "calling process (os.getpid()) instead of PID 0")
1179 try:
1180 os.kill(self.pid, sig)
1181 except ProcessLookupError:
1182 if OPENBSD and pid_exists(self.pid):
1183 # We do this because os.kill() lies in case of
1184 # zombie processes.
1185 raise ZombieProcess(self.pid, self._name, self._ppid)
1186 else:
1187 self._gone = True
1188 raise NoSuchProcess(self.pid, self._name)
1189 except PermissionError:
1190 raise AccessDenied(self.pid, self._name)
1192 @_assert_pid_not_reused
1193 def send_signal(self, sig):
1194 """Send a signal *sig* to process pre-emptively checking
1195 whether PID has been reused (see signal module constants) .
1196 On Windows only SIGTERM is valid and is treated as an alias
1197 for kill().
1198 """
1199 if POSIX:
1200 self._send_signal(sig)
1201 else: # pragma: no cover
1202 self._proc.send_signal(sig)
1204 @_assert_pid_not_reused
1205 def suspend(self):
1206 """Suspend process execution with SIGSTOP pre-emptively checking
1207 whether PID has been reused.
1208 On Windows this has the effect of suspending all process threads.
1209 """
1210 if POSIX:
1211 self._send_signal(signal.SIGSTOP)
1212 else: # pragma: no cover
1213 self._proc.suspend()
1215 @_assert_pid_not_reused
1216 def resume(self):
1217 """Resume process execution with SIGCONT pre-emptively checking
1218 whether PID has been reused.
1219 On Windows this has the effect of resuming all process threads.
1220 """
1221 if POSIX:
1222 self._send_signal(signal.SIGCONT)
1223 else: # pragma: no cover
1224 self._proc.resume()
1226 @_assert_pid_not_reused
1227 def terminate(self):
1228 """Terminate the process with SIGTERM pre-emptively checking
1229 whether PID has been reused.
1230 On Windows this is an alias for kill().
1231 """
1232 if POSIX:
1233 self._send_signal(signal.SIGTERM)
1234 else: # pragma: no cover
1235 self._proc.kill()
1237 @_assert_pid_not_reused
1238 def kill(self):
1239 """Kill the current process with SIGKILL pre-emptively checking
1240 whether PID has been reused.
1241 """
1242 if POSIX:
1243 self._send_signal(signal.SIGKILL)
1244 else: # pragma: no cover
1245 self._proc.kill()
1247 def wait(self, timeout=None):
1248 """Wait for process to terminate and, if process is a children
1249 of os.getpid(), also return its exit code, else None.
1250 On Windows there's no such limitation (exit code is always
1251 returned).
1253 If the process is already terminated immediately return None
1254 instead of raising NoSuchProcess.
1256 If *timeout* (in seconds) is specified and process is still
1257 alive raise TimeoutExpired.
1259 To wait for multiple Process(es) use psutil.wait_procs().
1260 """
1261 if timeout is not None and not timeout >= 0:
1262 raise ValueError("timeout must be a positive integer")
1263 if self._exitcode is not _SENTINEL:
1264 return self._exitcode
1265 self._exitcode = self._proc.wait(timeout)
1266 return self._exitcode
1269# The valid attr names which can be processed by Process.as_dict().
1270_as_dict_attrnames = set(
1271 [x for x in dir(Process) if not x.startswith('_') and x not in
1272 ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
1273 'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit',
1274 'memory_info_ex', 'oneshot']])
1277# =====================================================================
1278# --- Popen class
1279# =====================================================================
1282class Popen(Process):
1283 """Same as subprocess.Popen, but in addition it provides all
1284 psutil.Process methods in a single class.
1285 For the following methods which are common to both classes, psutil
1286 implementation takes precedence:
1288 * send_signal()
1289 * terminate()
1290 * kill()
1292 This is done in order to avoid killing another process in case its
1293 PID has been reused, fixing BPO-6973.
1295 >>> import psutil
1296 >>> from subprocess import PIPE
1297 >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE)
1298 >>> p.name()
1299 'python'
1300 >>> p.uids()
1301 user(real=1000, effective=1000, saved=1000)
1302 >>> p.username()
1303 'giampaolo'
1304 >>> p.communicate()
1305 ('hi\n', None)
1306 >>> p.terminate()
1307 >>> p.wait(timeout=2)
1308 0
1309 >>>
1310 """
1312 def __init__(self, *args, **kwargs):
1313 # Explicitly avoid to raise NoSuchProcess in case the process
1314 # spawned by subprocess.Popen terminates too quickly, see:
1315 # https://github.com/giampaolo/psutil/issues/193
1316 self.__subproc = subprocess.Popen(*args, **kwargs)
1317 self._init(self.__subproc.pid, _ignore_nsp=True)
1319 def __dir__(self):
1320 return sorted(set(dir(Popen) + dir(subprocess.Popen)))
1322 def __enter__(self):
1323 if hasattr(self.__subproc, '__enter__'):
1324 self.__subproc.__enter__()
1325 return self
1327 def __exit__(self, *args, **kwargs):
1328 if hasattr(self.__subproc, '__exit__'):
1329 return self.__subproc.__exit__(*args, **kwargs)
1330 else:
1331 if self.stdout:
1332 self.stdout.close()
1333 if self.stderr:
1334 self.stderr.close()
1335 try:
1336 # Flushing a BufferedWriter may raise an error.
1337 if self.stdin:
1338 self.stdin.close()
1339 finally:
1340 # Wait for the process to terminate, to avoid zombies.
1341 self.wait()
1343 def __getattribute__(self, name):
1344 try:
1345 return object.__getattribute__(self, name)
1346 except AttributeError:
1347 try:
1348 return object.__getattribute__(self.__subproc, name)
1349 except AttributeError:
1350 raise AttributeError("%s instance has no attribute '%s'"
1351 % (self.__class__.__name__, name))
1353 def wait(self, timeout=None):
1354 if self.__subproc.returncode is not None:
1355 return self.__subproc.returncode
1356 ret = super(Popen, self).wait(timeout)
1357 self.__subproc.returncode = ret
1358 return ret
1361# =====================================================================
1362# --- system processes related functions
1363# =====================================================================
1366def pids():
1367 """Return a list of current running PIDs."""
1368 global _LOWEST_PID
1369 ret = sorted(_psplatform.pids())
1370 _LOWEST_PID = ret[0]
1371 return ret
1374def pid_exists(pid):
1375 """Return True if given PID exists in the current process list.
1376 This is faster than doing "pid in psutil.pids()" and
1377 should be preferred.
1378 """
1379 if pid < 0:
1380 return False
1381 elif pid == 0 and POSIX:
1382 # On POSIX we use os.kill() to determine PID existence.
1383 # According to "man 2 kill" PID 0 has a special meaning
1384 # though: it refers to <<every process in the process
1385 # group of the calling process>> and that is not we want
1386 # to do here.
1387 return pid in pids()
1388 else:
1389 return _psplatform.pid_exists(pid)
1392_pmap = {}
1395def process_iter(attrs=None, ad_value=None):
1396 """Return a generator yielding a Process instance for all
1397 running processes.
1399 Every new Process instance is only created once and then cached
1400 into an internal table which is updated every time this is used.
1402 Cached Process instances are checked for identity so that you're
1403 safe in case a PID has been reused by another process, in which
1404 case the cached instance is updated.
1406 The sorting order in which processes are yielded is based on
1407 their PIDs.
1409 *attrs* and *ad_value* have the same meaning as in
1410 Process.as_dict(). If *attrs* is specified as_dict() is called
1411 and the resulting dict is stored as a 'info' attribute attached
1412 to returned Process instance.
1413 If *attrs* is an empty list it will retrieve all process info
1414 (slow).
1415 """
1416 global _pmap
1418 def add(pid):
1419 proc = Process(pid)
1420 if attrs is not None:
1421 proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
1422 pmap[proc.pid] = proc
1423 return proc
1425 def remove(pid):
1426 pmap.pop(pid, None)
1428 pmap = _pmap.copy()
1429 a = set(pids())
1430 b = set(pmap.keys())
1431 new_pids = a - b
1432 gone_pids = b - a
1433 for pid in gone_pids:
1434 remove(pid)
1435 try:
1436 ls = sorted(list(pmap.items()) + list(dict.fromkeys(new_pids).items()))
1437 for pid, proc in ls:
1438 try:
1439 if proc is None: # new process
1440 yield add(pid)
1441 else:
1442 # use is_running() to check whether PID has been
1443 # reused by another process in which case yield a
1444 # new Process instance
1445 if proc.is_running():
1446 if attrs is not None:
1447 proc.info = proc.as_dict(
1448 attrs=attrs, ad_value=ad_value)
1449 yield proc
1450 else:
1451 yield add(pid)
1452 except NoSuchProcess:
1453 remove(pid)
1454 except AccessDenied:
1455 # Process creation time can't be determined hence there's
1456 # no way to tell whether the pid of the cached process
1457 # has been reused. Just return the cached version.
1458 if proc is None and pid in pmap:
1459 try:
1460 yield pmap[pid]
1461 except KeyError:
1462 # If we get here it is likely that 2 threads were
1463 # using process_iter().
1464 pass
1465 else:
1466 raise
1467 finally:
1468 _pmap = pmap
1471def wait_procs(procs, timeout=None, callback=None):
1472 """Convenience function which waits for a list of processes to
1473 terminate.
1475 Return a (gone, alive) tuple indicating which processes
1476 are gone and which ones are still alive.
1478 The gone ones will have a new *returncode* attribute indicating
1479 process exit status (may be None).
1481 *callback* is a function which gets called every time a process
1482 terminates (a Process instance is passed as callback argument).
1484 Function will return as soon as all processes terminate or when
1485 *timeout* occurs.
1486 Differently from Process.wait() it will not raise TimeoutExpired if
1487 *timeout* occurs.
1489 Typical use case is:
1491 - send SIGTERM to a list of processes
1492 - give them some time to terminate
1493 - send SIGKILL to those ones which are still alive
1495 Example:
1497 >>> def on_terminate(proc):
1498 ... print("process {} terminated".format(proc))
1499 ...
1500 >>> for p in procs:
1501 ... p.terminate()
1502 ...
1503 >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate)
1504 >>> for p in alive:
1505 ... p.kill()
1506 """
1507 def check_gone(proc, timeout):
1508 try:
1509 returncode = proc.wait(timeout=timeout)
1510 except TimeoutExpired:
1511 pass
1512 except _SubprocessTimeoutExpired:
1513 pass
1514 else:
1515 if returncode is not None or not proc.is_running():
1516 # Set new Process instance attribute.
1517 proc.returncode = returncode
1518 gone.add(proc)
1519 if callback is not None:
1520 callback(proc)
1522 if timeout is not None and not timeout >= 0:
1523 msg = "timeout must be a positive integer, got %s" % timeout
1524 raise ValueError(msg)
1525 gone = set()
1526 alive = set(procs)
1527 if callback is not None and not callable(callback):
1528 raise TypeError("callback %r is not a callable" % callable)
1529 if timeout is not None:
1530 deadline = _timer() + timeout
1532 while alive:
1533 if timeout is not None and timeout <= 0:
1534 break
1535 for proc in alive:
1536 # Make sure that every complete iteration (all processes)
1537 # will last max 1 sec.
1538 # We do this because we don't want to wait too long on a
1539 # single process: in case it terminates too late other
1540 # processes may disappear in the meantime and their PID
1541 # reused.
1542 max_timeout = 1.0 / len(alive)
1543 if timeout is not None:
1544 timeout = min((deadline - _timer()), max_timeout)
1545 if timeout <= 0:
1546 break
1547 check_gone(proc, timeout)
1548 else:
1549 check_gone(proc, max_timeout)
1550 alive = alive - gone
1552 if alive:
1553 # Last attempt over processes survived so far.
1554 # timeout == 0 won't make this function wait any further.
1555 for proc in alive:
1556 check_gone(proc, 0)
1557 alive = alive - gone
1559 return (list(gone), list(alive))
1562# =====================================================================
1563# --- CPU related functions
1564# =====================================================================
1567def cpu_count(logical=True):
1568 """Return the number of logical CPUs in the system (same as
1569 os.cpu_count() in Python 3.4).
1571 If *logical* is False return the number of physical cores only
1572 (e.g. hyper thread CPUs are excluded).
1574 Return None if undetermined.
1576 The return value is cached after first call.
1577 If desired cache can be cleared like this:
1579 >>> psutil.cpu_count.cache_clear()
1580 """
1581 if logical:
1582 ret = _psplatform.cpu_count_logical()
1583 else:
1584 ret = _psplatform.cpu_count_cores()
1585 if ret is not None and ret < 1:
1586 ret = None
1587 return ret
1590def cpu_times(percpu=False):
1591 """Return system-wide CPU times as a namedtuple.
1592 Every CPU time represents the seconds the CPU has spent in the
1593 given mode. The namedtuple's fields availability varies depending on the
1594 platform:
1596 - user
1597 - system
1598 - idle
1599 - nice (UNIX)
1600 - iowait (Linux)
1601 - irq (Linux, FreeBSD)
1602 - softirq (Linux)
1603 - steal (Linux >= 2.6.11)
1604 - guest (Linux >= 2.6.24)
1605 - guest_nice (Linux >= 3.2.0)
1607 When *percpu* is True return a list of namedtuples for each CPU.
1608 First element of the list refers to first CPU, second element
1609 to second CPU and so on.
1610 The order of the list is consistent across calls.
1611 """
1612 if not percpu:
1613 return _psplatform.cpu_times()
1614 else:
1615 return _psplatform.per_cpu_times()
1618try:
1619 _last_cpu_times = cpu_times()
1620except Exception:
1621 # Don't want to crash at import time.
1622 _last_cpu_times = None
1624try:
1625 _last_per_cpu_times = cpu_times(percpu=True)
1626except Exception:
1627 # Don't want to crash at import time.
1628 _last_per_cpu_times = None
1631def _cpu_tot_time(times):
1632 """Given a cpu_time() ntuple calculates the total CPU time
1633 (including idle time).
1634 """
1635 tot = sum(times)
1636 if LINUX:
1637 # On Linux guest times are already accounted in "user" or
1638 # "nice" times, so we subtract them from total.
1639 # Htop does the same. References:
1640 # https://github.com/giampaolo/psutil/pull/940
1641 # http://unix.stackexchange.com/questions/178045
1642 # https://github.com/torvalds/linux/blob/
1643 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/
1644 # cputime.c#L158
1645 tot -= getattr(times, "guest", 0) # Linux 2.6.24+
1646 tot -= getattr(times, "guest_nice", 0) # Linux 3.2.0+
1647 return tot
1650def _cpu_busy_time(times):
1651 """Given a cpu_time() ntuple calculates the busy CPU time.
1652 We do so by subtracting all idle CPU times.
1653 """
1654 busy = _cpu_tot_time(times)
1655 busy -= times.idle
1656 # Linux: "iowait" is time during which the CPU does not do anything
1657 # (waits for IO to complete). On Linux IO wait is *not* accounted
1658 # in "idle" time so we subtract it. Htop does the same.
1659 # References:
1660 # https://github.com/torvalds/linux/blob/
1661 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244
1662 busy -= getattr(times, "iowait", 0)
1663 return busy
1666def _cpu_times_deltas(t1, t2):
1667 assert t1._fields == t2._fields, (t1, t2)
1668 field_deltas = []
1669 for field in _psplatform.scputimes._fields:
1670 field_delta = getattr(t2, field) - getattr(t1, field)
1671 # CPU times are always supposed to increase over time
1672 # or at least remain the same and that's because time
1673 # cannot go backwards.
1674 # Surprisingly sometimes this might not be the case (at
1675 # least on Windows and Linux), see:
1676 # https://github.com/giampaolo/psutil/issues/392
1677 # https://github.com/giampaolo/psutil/issues/645
1678 # https://github.com/giampaolo/psutil/issues/1210
1679 # Trim negative deltas to zero to ignore decreasing fields.
1680 # top does the same. Reference:
1681 # https://gitlab.com/procps-ng/procps/blob/v3.3.12/top/top.c#L5063
1682 field_delta = max(0, field_delta)
1683 field_deltas.append(field_delta)
1684 return _psplatform.scputimes(*field_deltas)
1687def cpu_percent(interval=None, percpu=False):
1688 """Return a float representing the current system-wide CPU
1689 utilization as a percentage.
1691 When *interval* is > 0.0 compares system CPU times elapsed before
1692 and after the interval (blocking).
1694 When *interval* is 0.0 or None compares system CPU times elapsed
1695 since last call or module import, returning immediately (non
1696 blocking). That means the first time this is called it will
1697 return a meaningless 0.0 value which you should ignore.
1698 In this case is recommended for accuracy that this function be
1699 called with at least 0.1 seconds between calls.
1701 When *percpu* is True returns a list of floats representing the
1702 utilization as a percentage for each CPU.
1703 First element of the list refers to first CPU, second element
1704 to second CPU and so on.
1705 The order of the list is consistent across calls.
1707 Examples:
1709 >>> # blocking, system-wide
1710 >>> psutil.cpu_percent(interval=1)
1711 2.0
1712 >>>
1713 >>> # blocking, per-cpu
1714 >>> psutil.cpu_percent(interval=1, percpu=True)
1715 [2.0, 1.0]
1716 >>>
1717 >>> # non-blocking (percentage since last call)
1718 >>> psutil.cpu_percent(interval=None)
1719 2.9
1720 >>>
1721 """
1722 global _last_cpu_times
1723 global _last_per_cpu_times
1724 blocking = interval is not None and interval > 0.0
1725 if interval is not None and interval < 0:
1726 raise ValueError("interval is not positive (got %r)" % interval)
1728 def calculate(t1, t2):
1729 times_delta = _cpu_times_deltas(t1, t2)
1730 all_delta = _cpu_tot_time(times_delta)
1731 busy_delta = _cpu_busy_time(times_delta)
1733 try:
1734 busy_perc = (busy_delta / all_delta) * 100
1735 except ZeroDivisionError:
1736 return 0.0
1737 else:
1738 return round(busy_perc, 1)
1740 # system-wide usage
1741 if not percpu:
1742 if blocking:
1743 t1 = cpu_times()
1744 time.sleep(interval)
1745 else:
1746 t1 = _last_cpu_times
1747 if t1 is None:
1748 # Something bad happened at import time. We'll
1749 # get a meaningful result on the next call. See:
1750 # https://github.com/giampaolo/psutil/pull/715
1751 t1 = cpu_times()
1752 _last_cpu_times = cpu_times()
1753 return calculate(t1, _last_cpu_times)
1754 # per-cpu usage
1755 else:
1756 ret = []
1757 if blocking:
1758 tot1 = cpu_times(percpu=True)
1759 time.sleep(interval)
1760 else:
1761 tot1 = _last_per_cpu_times
1762 if tot1 is None:
1763 # Something bad happened at import time. We'll
1764 # get a meaningful result on the next call. See:
1765 # https://github.com/giampaolo/psutil/pull/715
1766 tot1 = cpu_times(percpu=True)
1767 _last_per_cpu_times = cpu_times(percpu=True)
1768 for t1, t2 in zip(tot1, _last_per_cpu_times):
1769 ret.append(calculate(t1, t2))
1770 return ret
1773# Use separate global vars for cpu_times_percent() so that it's
1774# independent from cpu_percent() and they can both be used within
1775# the same program.
1776_last_cpu_times_2 = _last_cpu_times
1777_last_per_cpu_times_2 = _last_per_cpu_times
1780def cpu_times_percent(interval=None, percpu=False):
1781 """Same as cpu_percent() but provides utilization percentages
1782 for each specific CPU time as is returned by cpu_times().
1783 For instance, on Linux we'll get:
1785 >>> cpu_times_percent()
1786 cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0,
1787 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
1788 >>>
1790 *interval* and *percpu* arguments have the same meaning as in
1791 cpu_percent().
1792 """
1793 global _last_cpu_times_2
1794 global _last_per_cpu_times_2
1795 blocking = interval is not None and interval > 0.0
1796 if interval is not None and interval < 0:
1797 raise ValueError("interval is not positive (got %r)" % interval)
1799 def calculate(t1, t2):
1800 nums = []
1801 times_delta = _cpu_times_deltas(t1, t2)
1802 all_delta = _cpu_tot_time(times_delta)
1803 # "scale" is the value to multiply each delta with to get percentages.
1804 # We use "max" to avoid division by zero (if all_delta is 0, then all
1805 # fields are 0 so percentages will be 0 too. all_delta cannot be a
1806 # fraction because cpu times are integers)
1807 scale = 100.0 / max(1, all_delta)
1808 for field_delta in times_delta:
1809 field_perc = field_delta * scale
1810 field_perc = round(field_perc, 1)
1811 # make sure we don't return negative values or values over 100%
1812 field_perc = min(max(0.0, field_perc), 100.0)
1813 nums.append(field_perc)
1814 return _psplatform.scputimes(*nums)
1816 # system-wide usage
1817 if not percpu:
1818 if blocking:
1819 t1 = cpu_times()
1820 time.sleep(interval)
1821 else:
1822 t1 = _last_cpu_times_2
1823 if t1 is None:
1824 # Something bad happened at import time. We'll
1825 # get a meaningful result on the next call. See:
1826 # https://github.com/giampaolo/psutil/pull/715
1827 t1 = cpu_times()
1828 _last_cpu_times_2 = cpu_times()
1829 return calculate(t1, _last_cpu_times_2)
1830 # per-cpu usage
1831 else:
1832 ret = []
1833 if blocking:
1834 tot1 = cpu_times(percpu=True)
1835 time.sleep(interval)
1836 else:
1837 tot1 = _last_per_cpu_times_2
1838 if tot1 is None:
1839 # Something bad happened at import time. We'll
1840 # get a meaningful result on the next call. See:
1841 # https://github.com/giampaolo/psutil/pull/715
1842 tot1 = cpu_times(percpu=True)
1843 _last_per_cpu_times_2 = cpu_times(percpu=True)
1844 for t1, t2 in zip(tot1, _last_per_cpu_times_2):
1845 ret.append(calculate(t1, t2))
1846 return ret
1849def cpu_stats():
1850 """Return CPU statistics."""
1851 return _psplatform.cpu_stats()
1854if hasattr(_psplatform, "cpu_freq"):
1856 def cpu_freq(percpu=False):
1857 """Return CPU frequency as a namedtuple including current,
1858 min and max frequency expressed in Mhz.
1860 If *percpu* is True and the system supports per-cpu frequency
1861 retrieval (Linux only) a list of frequencies is returned for
1862 each CPU. If not a list with one element is returned.
1863 """
1864 ret = _psplatform.cpu_freq()
1865 if percpu:
1866 return ret
1867 else:
1868 num_cpus = float(len(ret))
1869 if num_cpus == 0:
1870 return None
1871 elif num_cpus == 1:
1872 return ret[0]
1873 else:
1874 currs, mins, maxs = 0.0, 0.0, 0.0
1875 set_none = False
1876 for cpu in ret:
1877 currs += cpu.current
1878 # On Linux if /proc/cpuinfo is used min/max are set
1879 # to None.
1880 if LINUX and cpu.min is None:
1881 set_none = True
1882 continue
1883 mins += cpu.min
1884 maxs += cpu.max
1886 current = currs / num_cpus
1888 if set_none:
1889 min_ = max_ = None
1890 else:
1891 min_ = mins / num_cpus
1892 max_ = maxs / num_cpus
1894 return _common.scpufreq(current, min_, max_)
1896 __all__.append("cpu_freq")
1899if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"):
1900 # Perform this hasattr check once on import time to either use the
1901 # platform based code or proxy straight from the os module.
1902 if hasattr(os, "getloadavg"):
1903 getloadavg = os.getloadavg
1904 else:
1905 getloadavg = _psplatform.getloadavg
1907 __all__.append("getloadavg")
1910# =====================================================================
1911# --- system memory related functions
1912# =====================================================================
1915def virtual_memory():
1916 """Return statistics about system memory usage as a namedtuple
1917 including the following fields, expressed in bytes:
1919 - total:
1920 total physical memory available.
1922 - available:
1923 the memory that can be given instantly to processes without the
1924 system going into swap.
1925 This is calculated by summing different memory values depending
1926 on the platform and it is supposed to be used to monitor actual
1927 memory usage in a cross platform fashion.
1929 - percent:
1930 the percentage usage calculated as (total - available) / total * 100
1932 - used:
1933 memory used, calculated differently depending on the platform and
1934 designed for informational purposes only:
1935 macOS: active + wired
1936 BSD: active + wired + cached
1937 Linux: total - free
1939 - free:
1940 memory not being used at all (zeroed) that is readily available;
1941 note that this doesn't reflect the actual memory available
1942 (use 'available' instead)
1944 Platform-specific fields:
1946 - active (UNIX):
1947 memory currently in use or very recently used, and so it is in RAM.
1949 - inactive (UNIX):
1950 memory that is marked as not used.
1952 - buffers (BSD, Linux):
1953 cache for things like file system metadata.
1955 - cached (BSD, macOS):
1956 cache for various things.
1958 - wired (macOS, BSD):
1959 memory that is marked to always stay in RAM. It is never moved to disk.
1961 - shared (BSD):
1962 memory that may be simultaneously accessed by multiple processes.
1964 The sum of 'used' and 'available' does not necessarily equal total.
1965 On Windows 'available' and 'free' are the same.
1966 """
1967 global _TOTAL_PHYMEM
1968 ret = _psplatform.virtual_memory()
1969 # cached for later use in Process.memory_percent()
1970 _TOTAL_PHYMEM = ret.total
1971 return ret
1974def swap_memory():
1975 """Return system swap memory statistics as a namedtuple including
1976 the following fields:
1978 - total: total swap memory in bytes
1979 - used: used swap memory in bytes
1980 - free: free swap memory in bytes
1981 - percent: the percentage usage
1982 - sin: no. of bytes the system has swapped in from disk (cumulative)
1983 - sout: no. of bytes the system has swapped out from disk (cumulative)
1985 'sin' and 'sout' on Windows are meaningless and always set to 0.
1986 """
1987 return _psplatform.swap_memory()
1990# =====================================================================
1991# --- disks/paritions related functions
1992# =====================================================================
1995def disk_usage(path):
1996 """Return disk usage statistics about the given *path* as a
1997 namedtuple including total, used and free space expressed in bytes
1998 plus the percentage usage.
1999 """
2000 return _psplatform.disk_usage(path)
2003def disk_partitions(all=False):
2004 """Return mounted partitions as a list of
2005 (device, mountpoint, fstype, opts) namedtuple.
2006 'opts' field is a raw string separated by commas indicating mount
2007 options which may vary depending on the platform.
2009 If *all* parameter is False return physical devices only and ignore
2010 all others.
2011 """
2012 def pathconf(path, name):
2013 try:
2014 return os.pathconf(path, name)
2015 except (OSError, AttributeError):
2016 pass
2018 ret = _psplatform.disk_partitions(all)
2019 if POSIX:
2020 new = []
2021 for item in ret:
2022 nt = item._replace(
2023 maxfile=pathconf(item.mountpoint, 'PC_NAME_MAX'),
2024 maxpath=pathconf(item.mountpoint, 'PC_PATH_MAX'))
2025 new.append(nt)
2026 return new
2027 else:
2028 return ret
2031def disk_io_counters(perdisk=False, nowrap=True):
2032 """Return system disk I/O statistics as a namedtuple including
2033 the following fields:
2035 - read_count: number of reads
2036 - write_count: number of writes
2037 - read_bytes: number of bytes read
2038 - write_bytes: number of bytes written
2039 - read_time: time spent reading from disk (in ms)
2040 - write_time: time spent writing to disk (in ms)
2042 Platform specific:
2044 - busy_time: (Linux, FreeBSD) time spent doing actual I/Os (in ms)
2045 - read_merged_count (Linux): number of merged reads
2046 - write_merged_count (Linux): number of merged writes
2048 If *perdisk* is True return the same information for every
2049 physical disk installed on the system as a dictionary
2050 with partition names as the keys and the namedtuple
2051 described above as the values.
2053 If *nowrap* is True it detects and adjust the numbers which overflow
2054 and wrap (restart from 0) and add "old value" to "new value" so that
2055 the returned numbers will always be increasing or remain the same,
2056 but never decrease.
2057 "disk_io_counters.cache_clear()" can be used to invalidate the
2058 cache.
2060 On recent Windows versions 'diskperf -y' command may need to be
2061 executed first otherwise this function won't find any disk.
2062 """
2063 kwargs = dict(perdisk=perdisk) if LINUX else {}
2064 rawdict = _psplatform.disk_io_counters(**kwargs)
2065 if not rawdict:
2066 return {} if perdisk else None
2067 if nowrap:
2068 rawdict = _wrap_numbers(rawdict, 'psutil.disk_io_counters')
2069 nt = getattr(_psplatform, "sdiskio", _common.sdiskio)
2070 if perdisk:
2071 for disk, fields in rawdict.items():
2072 rawdict[disk] = nt(*fields)
2073 return rawdict
2074 else:
2075 return nt(*(sum(x) for x in zip(*rawdict.values())))
2078disk_io_counters.cache_clear = functools.partial(
2079 _wrap_numbers.cache_clear, 'psutil.disk_io_counters')
2080disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2083# =====================================================================
2084# --- network related functions
2085# =====================================================================
2088def net_io_counters(pernic=False, nowrap=True):
2089 """Return network I/O statistics as a namedtuple including
2090 the following fields:
2092 - bytes_sent: number of bytes sent
2093 - bytes_recv: number of bytes received
2094 - packets_sent: number of packets sent
2095 - packets_recv: number of packets received
2096 - errin: total number of errors while receiving
2097 - errout: total number of errors while sending
2098 - dropin: total number of incoming packets which were dropped
2099 - dropout: total number of outgoing packets which were dropped
2100 (always 0 on macOS and BSD)
2102 If *pernic* is True return the same information for every
2103 network interface installed on the system as a dictionary
2104 with network interface names as the keys and the namedtuple
2105 described above as the values.
2107 If *nowrap* is True it detects and adjust the numbers which overflow
2108 and wrap (restart from 0) and add "old value" to "new value" so that
2109 the returned numbers will always be increasing or remain the same,
2110 but never decrease.
2111 "disk_io_counters.cache_clear()" can be used to invalidate the
2112 cache.
2113 """
2114 rawdict = _psplatform.net_io_counters()
2115 if not rawdict:
2116 return {} if pernic else None
2117 if nowrap:
2118 rawdict = _wrap_numbers(rawdict, 'psutil.net_io_counters')
2119 if pernic:
2120 for nic, fields in rawdict.items():
2121 rawdict[nic] = _common.snetio(*fields)
2122 return rawdict
2123 else:
2124 return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
2127net_io_counters.cache_clear = functools.partial(
2128 _wrap_numbers.cache_clear, 'psutil.net_io_counters')
2129net_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
2132def net_connections(kind='inet'):
2133 """Return system-wide socket connections as a list of
2134 (fd, family, type, laddr, raddr, status, pid) namedtuples.
2135 In case of limited privileges 'fd' and 'pid' may be set to -1
2136 and None respectively.
2137 The *kind* parameter filters for connections that fit the
2138 following criteria:
2140 +------------+----------------------------------------------------+
2141 | Kind Value | Connections using |
2142 +------------+----------------------------------------------------+
2143 | inet | IPv4 and IPv6 |
2144 | inet4 | IPv4 |
2145 | inet6 | IPv6 |
2146 | tcp | TCP |
2147 | tcp4 | TCP over IPv4 |
2148 | tcp6 | TCP over IPv6 |
2149 | udp | UDP |
2150 | udp4 | UDP over IPv4 |
2151 | udp6 | UDP over IPv6 |
2152 | unix | UNIX socket (both UDP and TCP protocols) |
2153 | all | the sum of all the possible families and protocols |
2154 +------------+----------------------------------------------------+
2156 On macOS this function requires root privileges.
2157 """
2158 return _psplatform.net_connections(kind)
2161def net_if_addrs():
2162 """Return the addresses associated to each NIC (network interface
2163 card) installed on the system as a dictionary whose keys are the
2164 NIC names and value is a list of namedtuples for each address
2165 assigned to the NIC. Each namedtuple includes 5 fields:
2167 - family: can be either socket.AF_INET, socket.AF_INET6 or
2168 psutil.AF_LINK, which refers to a MAC address.
2169 - address: is the primary address and it is always set.
2170 - netmask: and 'broadcast' and 'ptp' may be None.
2171 - ptp: stands for "point to point" and references the
2172 destination address on a point to point interface
2173 (typically a VPN).
2174 - broadcast: and *ptp* are mutually exclusive.
2176 Note: you can have more than one address of the same family
2177 associated with each interface.
2178 """
2179 has_enums = sys.version_info >= (3, 4)
2180 if has_enums:
2181 import socket
2182 rawlist = _psplatform.net_if_addrs()
2183 rawlist.sort(key=lambda x: x[1]) # sort by family
2184 ret = collections.defaultdict(list)
2185 for name, fam, addr, mask, broadcast, ptp in rawlist:
2186 if has_enums:
2187 try:
2188 fam = socket.AddressFamily(fam)
2189 except ValueError:
2190 if WINDOWS and fam == -1:
2191 fam = _psplatform.AF_LINK
2192 elif (hasattr(_psplatform, "AF_LINK") and
2193 _psplatform.AF_LINK == fam):
2194 # Linux defines AF_LINK as an alias for AF_PACKET.
2195 # We re-set the family here so that repr(family)
2196 # will show AF_LINK rather than AF_PACKET
2197 fam = _psplatform.AF_LINK
2198 if fam == _psplatform.AF_LINK:
2199 # The underlying C function may return an incomplete MAC
2200 # address in which case we fill it with null bytes, see:
2201 # https://github.com/giampaolo/psutil/issues/786
2202 separator = ":" if POSIX else "-"
2203 while addr.count(separator) < 5:
2204 addr += "%s00" % separator
2205 ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp))
2206 return dict(ret)
2209def net_if_stats():
2210 """Return information about each NIC (network interface card)
2211 installed on the system as a dictionary whose keys are the
2212 NIC names and value is a namedtuple with the following fields:
2214 - isup: whether the interface is up (bool)
2215 - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or
2216 NIC_DUPLEX_UNKNOWN
2217 - speed: the NIC speed expressed in mega bits (MB); if it can't
2218 be determined (e.g. 'localhost') it will be set to 0.
2219 - mtu: the maximum transmission unit expressed in bytes.
2220 """
2221 return _psplatform.net_if_stats()
2224# =====================================================================
2225# --- sensors
2226# =====================================================================
2229# Linux, macOS
2230if hasattr(_psplatform, "sensors_temperatures"):
2232 def sensors_temperatures(fahrenheit=False):
2233 """Return hardware temperatures. Each entry is a namedtuple
2234 representing a certain hardware sensor (it may be a CPU, an
2235 hard disk or something else, depending on the OS and its
2236 configuration).
2237 All temperatures are expressed in celsius unless *fahrenheit*
2238 is set to True.
2239 """
2240 def convert(n):
2241 if n is not None:
2242 return (float(n) * 9 / 5) + 32 if fahrenheit else n
2244 ret = collections.defaultdict(list)
2245 rawdict = _psplatform.sensors_temperatures()
2247 for name, values in rawdict.items():
2248 while values:
2249 label, current, high, critical = values.pop(0)
2250 current = convert(current)
2251 high = convert(high)
2252 critical = convert(critical)
2254 if high and not critical:
2255 critical = high
2256 elif critical and not high:
2257 high = critical
2259 ret[name].append(
2260 _common.shwtemp(label, current, high, critical))
2262 return dict(ret)
2264 __all__.append("sensors_temperatures")
2267# Linux
2268if hasattr(_psplatform, "sensors_fans"):
2270 def sensors_fans():
2271 """Return fans speed. Each entry is a namedtuple
2272 representing a certain hardware sensor.
2273 All speed are expressed in RPM (rounds per minute).
2274 """
2275 return _psplatform.sensors_fans()
2277 __all__.append("sensors_fans")
2280# Linux, Windows, FreeBSD, macOS
2281if hasattr(_psplatform, "sensors_battery"):
2283 def sensors_battery():
2284 """Return battery information. If no battery is installed
2285 returns None.
2287 - percent: battery power left as a percentage.
2288 - secsleft: a rough approximation of how many seconds are left
2289 before the battery runs out of power. May be
2290 POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED.
2291 - power_plugged: True if the AC power cable is connected.
2292 """
2293 return _psplatform.sensors_battery()
2295 __all__.append("sensors_battery")
2298# =====================================================================
2299# --- other system related functions
2300# =====================================================================
2303def boot_time():
2304 """Return the system boot time expressed in seconds since the epoch."""
2305 # Note: we are not caching this because it is subject to
2306 # system clock updates.
2307 return _psplatform.boot_time()
2310def users():
2311 """Return users currently connected on the system as a list of
2312 namedtuples including the following fields.
2314 - user: the name of the user
2315 - terminal: the tty or pseudo-tty associated with the user, if any.
2316 - host: the host name associated with the entry, if any.
2317 - started: the creation time as a floating point number expressed in
2318 seconds since the epoch.
2319 """
2320 return _psplatform.users()
2323# =====================================================================
2324# --- Windows services
2325# =====================================================================
2328if WINDOWS:
2330 def win_service_iter():
2331 """Return a generator yielding a WindowsService instance for all
2332 Windows services installed.
2333 """
2334 return _psplatform.win_service_iter()
2336 def win_service_get(name):
2337 """Get a Windows service by *name*.
2338 Raise NoSuchProcess if no service with such name exists.
2339 """
2340 return _psplatform.win_service_get(name)
2343# =====================================================================
2346def _set_debug(value):
2347 """Enable or disable PSUTIL_DEBUG option, which prints debugging
2348 messages to stderr.
2349 """
2350 import psutil._common
2351 psutil._common.PSUTIL_DEBUG = bool(value)
2352 _psplatform.cext.set_debug(bool(value))
2355def test(): # pragma: no cover
2356 from ._common import bytes2human
2357 from ._compat import get_terminal_size
2359 today_day = datetime.date.today()
2360 templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s %s"
2361 attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times',
2362 'create_time', 'memory_info', 'status', 'nice', 'username']
2363 print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE", # NOQA
2364 "STATUS", "START", "TIME", "CMDLINE"))
2365 for p in process_iter(attrs, ad_value=None):
2366 if p.info['create_time']:
2367 ctime = datetime.datetime.fromtimestamp(p.info['create_time'])
2368 if ctime.date() == today_day:
2369 ctime = ctime.strftime("%H:%M")
2370 else:
2371 ctime = ctime.strftime("%b%d")
2372 else:
2373 ctime = ''
2374 if p.info['cpu_times']:
2375 cputime = time.strftime("%M:%S",
2376 time.localtime(sum(p.info['cpu_times'])))
2377 else:
2378 cputime = ''
2380 user = p.info['username'] or ''
2381 if not user and POSIX:
2382 try:
2383 user = p.uids()[0]
2384 except Error:
2385 pass
2386 if user and WINDOWS and '\\' in user:
2387 user = user.split('\\')[1]
2388 user = user[:9]
2389 vms = bytes2human(p.info['memory_info'].vms) if \
2390 p.info['memory_info'] is not None else ''
2391 rss = bytes2human(p.info['memory_info'].rss) if \
2392 p.info['memory_info'] is not None else ''
2393 memp = round(p.info['memory_percent'], 1) if \
2394 p.info['memory_percent'] is not None else ''
2395 nice = int(p.info['nice']) if p.info['nice'] else ''
2396 if p.info['cmdline']:
2397 cmdline = ' '.join(p.info['cmdline'])
2398 else:
2399 cmdline = p.info['name']
2400 status = p.info['status'][:5] if p.info['status'] else ''
2402 line = templ % (
2403 user[:10],
2404 p.info['pid'],
2405 memp,
2406 vms,
2407 rss,
2408 nice,
2409 status,
2410 ctime,
2411 cputime,
2412 cmdline)
2413 print(line[:get_terminal_size()[0]]) # NOQA
2416del memoize_when_activated, division
2417if sys.version_info[0] < 3:
2418 del num, x
2420if __name__ == "__main__":
2421 test()