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