comparison env/lib/python3.9/site-packages/psutil/__init__.py @ 0:4f3585e2f14b draft default tip

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