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