1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8"""psutil is a cross-platform library for retrieving information on 9running processes and system utilization (CPU, memory, disks, network) 10in Python. 11""" 12 13from __future__ import division 14 15import collections 16import errno 17import functools 18import os 19import signal 20import subprocess 21import sys 22import time 23try: 24 import pwd 25except ImportError: 26 pwd = None 27 28from . import _common 29from ._common import memoize 30from ._compat import callable, long 31from ._compat import PY3 as _PY3 32 33from ._common import (STATUS_RUNNING, # NOQA 34 STATUS_SLEEPING, 35 STATUS_DISK_SLEEP, 36 STATUS_STOPPED, 37 STATUS_TRACING_STOP, 38 STATUS_ZOMBIE, 39 STATUS_DEAD, 40 STATUS_WAKING, 41 STATUS_LOCKED, 42 STATUS_IDLE, # bsd 43 STATUS_WAITING) # bsd 44 45from ._common import (CONN_ESTABLISHED, 46 CONN_SYN_SENT, 47 CONN_SYN_RECV, 48 CONN_FIN_WAIT1, 49 CONN_FIN_WAIT2, 50 CONN_TIME_WAIT, 51 CONN_CLOSE, 52 CONN_CLOSE_WAIT, 53 CONN_LAST_ACK, 54 CONN_LISTEN, 55 CONN_CLOSING, 56 CONN_NONE) 57 58from ._common import (NIC_DUPLEX_FULL, # NOQA 59 NIC_DUPLEX_HALF, 60 NIC_DUPLEX_UNKNOWN) 61 62if sys.platform.startswith("linux"): 63 from . import _pslinux as _psplatform 64 65 from ._pslinux import (IOPRIO_CLASS_NONE, # NOQA 66 IOPRIO_CLASS_RT, 67 IOPRIO_CLASS_BE, 68 IOPRIO_CLASS_IDLE) 69 # Linux >= 2.6.36 70 if _psplatform.HAS_PRLIMIT: 71 from ._psutil_linux import (RLIM_INFINITY, # NOQA 72 RLIMIT_AS, 73 RLIMIT_CORE, 74 RLIMIT_CPU, 75 RLIMIT_DATA, 76 RLIMIT_FSIZE, 77 RLIMIT_LOCKS, 78 RLIMIT_MEMLOCK, 79 RLIMIT_NOFILE, 80 RLIMIT_NPROC, 81 RLIMIT_RSS, 82 RLIMIT_STACK) 83 # Kinda ugly but considerably faster than using hasattr() and 84 # setattr() against the module object (we are at import time: 85 # speed matters). 86 from . import _psutil_linux 87 try: 88 RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE 89 except AttributeError: 90 pass 91 try: 92 RLIMIT_NICE = _psutil_linux.RLIMIT_NICE 93 except AttributeError: 94 pass 95 try: 96 RLIMIT_RTPRIO = _psutil_linux.RLIMIT_RTPRIO 97 except AttributeError: 98 pass 99 try: 100 RLIMIT_RTTIME = _psutil_linux.RLIMIT_RTTIME 101 except AttributeError: 102 pass 103 try: 104 RLIMIT_SIGPENDING = _psutil_linux.RLIMIT_SIGPENDING 105 except AttributeError: 106 pass 107 del _psutil_linux 108 109elif sys.platform.startswith("win32"): 110 from . import _pswindows as _psplatform 111 from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA 112 BELOW_NORMAL_PRIORITY_CLASS, 113 HIGH_PRIORITY_CLASS, 114 IDLE_PRIORITY_CLASS, 115 NORMAL_PRIORITY_CLASS, 116 REALTIME_PRIORITY_CLASS) 117 from ._pswindows import CONN_DELETE_TCB # NOQA 118 119elif sys.platform.startswith("darwin"): 120 from . import _psosx as _psplatform 121 122elif sys.platform.startswith("freebsd"): 123 from . import _psbsd as _psplatform 124 125elif sys.platform.startswith("sunos"): 126 from . import _pssunos as _psplatform 127 from ._pssunos import (CONN_IDLE, # NOQA 128 CONN_BOUND) 129 130else: # pragma: no cover 131 raise NotImplementedError('platform %s is not supported' % sys.platform) 132 133 134__all__ = [ 135 # exceptions 136 "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied", 137 "TimeoutExpired", 138 # constants 139 "version_info", "__version__", 140 "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", 141 "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", 142 "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", 143 "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", 144 "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", 145 "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", 146 "AF_LINK", 147 "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN", 148 # classes 149 "Process", "Popen", 150 # functions 151 "pid_exists", "pids", "process_iter", "wait_procs", # proc 152 "virtual_memory", "swap_memory", # memory 153 "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu 154 "net_io_counters", "net_connections", "net_if_addrs", # network 155 "net_if_stats", 156 "disk_io_counters", "disk_partitions", "disk_usage", # disk 157 "users", "boot_time", # others 158] 159__all__.extend(_psplatform.__extra__all__) 160__author__ = "Giampaolo Rodola'" 161__version__ = "3.1.1" 162version_info = tuple([int(num) for num in __version__.split('.')]) 163AF_LINK = _psplatform.AF_LINK 164_TOTAL_PHYMEM = None 165_POSIX = os.name == 'posix' 166_WINDOWS = os.name == 'nt' 167_timer = getattr(time, 'monotonic', time.time) 168 169 170# Sanity check in case the user messed up with psutil installation 171# or did something weird with sys.path. In this case we might end 172# up importing a python module using a C extension module which 173# was compiled for a different version of psutil. 174# We want to prevent that by failing sooner rather than later. 175# See: https://github.com/giampaolo/psutil/issues/564 176if (int(__version__.replace('.', '')) != 177 getattr(_psplatform.cext, 'version', None)): 178 msg = "version conflict: %r C extension module was built for another " \ 179 "version of psutil (different than %s)" % (_psplatform.cext.__file__, 180 __version__) 181 raise ImportError(msg) 182 183 184# ===================================================================== 185# --- exceptions 186# ===================================================================== 187 188class Error(Exception): 189 """Base exception class. All other psutil exceptions inherit 190 from this one. 191 """ 192 193 def __init__(self, msg=""): 194 self.msg = msg 195 196 def __repr__(self): 197 ret = "%s.%s %s" % (self.__class__.__module__, 198 self.__class__.__name__, self.msg) 199 return ret.strip() 200 201 __str__ = __repr__ 202 203 204class NoSuchProcess(Error): 205 """Exception raised when a process with a certain PID doesn't 206 or no longer exists. 207 """ 208 209 def __init__(self, pid, name=None, msg=None): 210 Error.__init__(self, msg) 211 self.pid = pid 212 self.name = name 213 self.msg = msg 214 if msg is None: 215 if name: 216 details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) 217 else: 218 details = "(pid=%s)" % self.pid 219 self.msg = "process no longer exists " + details 220 221 222class ZombieProcess(NoSuchProcess): 223 """Exception raised when querying a zombie process. This is 224 raised on OSX, BSD and Solaris only, and not always: depending 225 on the query the OS may be able to succeed anyway. 226 On Linux all zombie processes are querable (hence this is never 227 raised). Windows doesn't have zombie processes. 228 """ 229 230 def __init__(self, pid, name=None, ppid=None, msg=None): 231 Error.__init__(self, msg) 232 self.pid = pid 233 self.ppid = ppid 234 self.name = name 235 self.msg = msg 236 if msg is None: 237 if name and ppid: 238 details = "(pid=%s, name=%s, ppid=%s)" % ( 239 self.pid, repr(self.name), self.ppid) 240 elif name: 241 details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) 242 else: 243 details = "(pid=%s)" % self.pid 244 self.msg = "process still exists but it's a zombie " + details 245 246 247class AccessDenied(Error): 248 """Exception raised when permission to perform an action is denied.""" 249 250 def __init__(self, pid=None, name=None, msg=None): 251 Error.__init__(self, msg) 252 self.pid = pid 253 self.name = name 254 self.msg = msg 255 if msg is None: 256 if (pid is not None) and (name is not None): 257 self.msg = "(pid=%s, name=%s)" % (pid, repr(name)) 258 elif (pid is not None): 259 self.msg = "(pid=%s)" % self.pid 260 else: 261 self.msg = "" 262 263 264class TimeoutExpired(Error): 265 """Raised on Process.wait(timeout) if timeout expires and process 266 is still alive. 267 """ 268 269 def __init__(self, seconds, pid=None, name=None): 270 Error.__init__(self, "timeout after %s seconds" % seconds) 271 self.seconds = seconds 272 self.pid = pid 273 self.name = name 274 if (pid is not None) and (name is not None): 275 self.msg += " (pid=%s, name=%s)" % (pid, repr(name)) 276 elif (pid is not None): 277 self.msg += " (pid=%s)" % self.pid 278 279 280# push exception classes into platform specific module namespace 281_psplatform.NoSuchProcess = NoSuchProcess 282_psplatform.ZombieProcess = ZombieProcess 283_psplatform.AccessDenied = AccessDenied 284_psplatform.TimeoutExpired = TimeoutExpired 285 286 287# ===================================================================== 288# --- Process class 289# ===================================================================== 290 291 292def _assert_pid_not_reused(fun): 293 """Decorator which raises NoSuchProcess in case a process is no 294 longer running or its PID has been reused. 295 """ 296 @functools.wraps(fun) 297 def wrapper(self, *args, **kwargs): 298 if not self.is_running(): 299 raise NoSuchProcess(self.pid, self._name) 300 return fun(self, *args, **kwargs) 301 return wrapper 302 303 304class Process(object): 305 """Represents an OS process with the given PID. 306 If PID is omitted current process PID (os.getpid()) is used. 307 Raise NoSuchProcess if PID does not exist. 308 309 Note that most of the methods of this class do not make sure 310 the PID of the process being queried has been reused over time. 311 That means you might end up retrieving an information referring 312 to another process in case the original one this instance 313 refers to is gone in the meantime. 314 315 The only exceptions for which process identity is pre-emptively 316 checked and guaranteed are: 317 318 - parent() 319 - children() 320 - nice() (set) 321 - ionice() (set) 322 - rlimit() (set) 323 - cpu_affinity (set) 324 - suspend() 325 - resume() 326 - send_signal() 327 - terminate() 328 - kill() 329 330 To prevent this problem for all other methods you can: 331 - use is_running() before querying the process 332 - if you're continuously iterating over a set of Process 333 instances use process_iter() which pre-emptively checks 334 process identity for every yielded instance 335 """ 336 337 def __init__(self, pid=None): 338 self._init(pid) 339 340 def _init(self, pid, _ignore_nsp=False): 341 if pid is None: 342 pid = os.getpid() 343 else: 344 if not _PY3 and not isinstance(pid, (int, long)): 345 raise TypeError('pid must be an integer (got %r)' % pid) 346 if pid < 0: 347 raise ValueError('pid must be a positive integer (got %s)' 348 % pid) 349 self._pid = pid 350 self._name = None 351 self._exe = None 352 self._create_time = None 353 self._gone = False 354 self._hash = None 355 # used for caching on Windows only (on POSIX ppid may change) 356 self._ppid = None 357 # platform-specific modules define an _psplatform.Process 358 # implementation class 359 self._proc = _psplatform.Process(pid) 360 self._last_sys_cpu_times = None 361 self._last_proc_cpu_times = None 362 # cache creation time for later use in is_running() method 363 try: 364 self.create_time() 365 except AccessDenied: 366 # we should never get here as AFAIK we're able to get 367 # process creation time on all platforms even as a 368 # limited user 369 pass 370 except ZombieProcess: 371 # Let's consider a zombie process as legitimate as 372 # tehcnically it's still alive (it can be queried, 373 # although not always, and it's returned by pids()). 374 pass 375 except NoSuchProcess: 376 if not _ignore_nsp: 377 msg = 'no process found with pid %s' % pid 378 raise NoSuchProcess(pid, None, msg) 379 else: 380 self._gone = True 381 # This pair is supposed to indentify a Process instance 382 # univocally over time (the PID alone is not enough as 383 # it might refer to a process whose PID has been reused). 384 # This will be used later in __eq__() and is_running(). 385 self._ident = (self.pid, self._create_time) 386 387 def __str__(self): 388 try: 389 pid = self.pid 390 name = repr(self.name()) 391 except ZombieProcess: 392 details = "(pid=%s (zombie))" % self.pid 393 except NoSuchProcess: 394 details = "(pid=%s (terminated))" % self.pid 395 except AccessDenied: 396 details = "(pid=%s)" % (self.pid) 397 else: 398 details = "(pid=%s, name=%s)" % (pid, name) 399 return "%s.%s%s" % (self.__class__.__module__, 400 self.__class__.__name__, details) 401 402 def __repr__(self): 403 return "<%s at %s>" % (self.__str__(), id(self)) 404 405 def __eq__(self, other): 406 # Test for equality with another Process object based 407 # on PID and creation time. 408 if not isinstance(other, Process): 409 return NotImplemented 410 return self._ident == other._ident 411 412 def __ne__(self, other): 413 return not self == other 414 415 def __hash__(self): 416 if self._hash is None: 417 self._hash = hash(self._ident) 418 return self._hash 419 420 # --- utility methods 421 422 def as_dict(self, attrs=None, ad_value=None): 423 """Utility method returning process information as a 424 hashable dictionary. 425 426 If 'attrs' is specified it must be a list of strings 427 reflecting available Process class' attribute names 428 (e.g. ['cpu_times', 'name']) else all public (read 429 only) attributes are assumed. 430 431 'ad_value' is the value which gets assigned in case 432 AccessDenied or ZombieProcess exception is raised when 433 retrieving that particular process information. 434 """ 435 excluded_names = set( 436 ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 437 'is_running', 'as_dict', 'parent', 'children', 'rlimit']) 438 retdict = dict() 439 ls = set(attrs or [x for x in dir(self)]) 440 for name in ls: 441 if name.startswith('_'): 442 continue 443 if name in excluded_names: 444 continue 445 try: 446 attr = getattr(self, name) 447 if callable(attr): 448 ret = attr() 449 else: 450 ret = attr 451 except (AccessDenied, ZombieProcess): 452 ret = ad_value 453 except NotImplementedError: 454 # in case of not implemented functionality (may happen 455 # on old or exotic systems) we want to crash only if 456 # the user explicitly asked for that particular attr 457 if attrs: 458 raise 459 continue 460 retdict[name] = ret 461 return retdict 462 463 def parent(self): 464 """Return the parent process as a Process object pre-emptively 465 checking whether PID has been reused. 466 If no parent is known return None. 467 """ 468 ppid = self.ppid() 469 if ppid is not None: 470 ctime = self.create_time() 471 try: 472 parent = Process(ppid) 473 if parent.create_time() <= ctime: 474 return parent 475 # ...else ppid has been reused by another process 476 except NoSuchProcess: 477 pass 478 479 def is_running(self): 480 """Return whether this process is running. 481 It also checks if PID has been reused by another process in 482 which case return False. 483 """ 484 if self._gone: 485 return False 486 try: 487 # Checking if PID is alive is not enough as the PID might 488 # have been reused by another process: we also want to 489 # check process identity. 490 # Process identity / uniqueness over time is greanted by 491 # (PID + creation time) and that is verified in __eq__. 492 return self == Process(self.pid) 493 except NoSuchProcess: 494 self._gone = True 495 return False 496 497 # --- actual API 498 499 @property 500 def pid(self): 501 """The process PID.""" 502 return self._pid 503 504 def ppid(self): 505 """The process parent PID. 506 On Windows the return value is cached after first call. 507 """ 508 # On POSIX we don't want to cache the ppid as it may unexpectedly 509 # change to 1 (init) in case this process turns into a zombie: 510 # https://github.com/giampaolo/psutil/issues/321 511 # http://stackoverflow.com/questions/356722/ 512 513 # XXX should we check creation time here rather than in 514 # Process.parent()? 515 if _POSIX: 516 return self._proc.ppid() 517 else: 518 self._ppid = self._ppid or self._proc.ppid() 519 return self._ppid 520 521 def name(self): 522 """The process name. The return value is cached after first call.""" 523 if self._name is None: 524 name = self._proc.name() 525 if _POSIX and len(name) >= 15: 526 # On UNIX the name gets truncated to the first 15 characters. 527 # If it matches the first part of the cmdline we return that 528 # one instead because it's usually more explicative. 529 # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon". 530 try: 531 cmdline = self.cmdline() 532 except AccessDenied: 533 pass 534 else: 535 if cmdline: 536 extended_name = os.path.basename(cmdline[0]) 537 if extended_name.startswith(name): 538 name = extended_name 539 self._proc._name = name 540 self._name = name 541 return self._name 542 543 def exe(self): 544 """The process executable as an absolute path. 545 May also be an empty string. 546 The return value is cached after first call. 547 """ 548 def guess_it(fallback): 549 # try to guess exe from cmdline[0] in absence of a native 550 # exe representation 551 cmdline = self.cmdline() 552 if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'): 553 exe = cmdline[0] # the possible exe 554 # Attempt to guess only in case of an absolute path. 555 # It is not safe otherwise as the process might have 556 # changed cwd. 557 if (os.path.isabs(exe) and 558 os.path.isfile(exe) and 559 os.access(exe, os.X_OK)): 560 return exe 561 if isinstance(fallback, AccessDenied): 562 raise fallback 563 return fallback 564 565 if self._exe is None: 566 try: 567 exe = self._proc.exe() 568 except AccessDenied as err: 569 return guess_it(fallback=err) 570 else: 571 if not exe: 572 # underlying implementation can legitimately return an 573 # empty string; if that's the case we don't want to 574 # raise AD while guessing from the cmdline 575 try: 576 exe = guess_it(fallback=exe) 577 except AccessDenied: 578 pass 579 self._exe = exe 580 return self._exe 581 582 def cmdline(self): 583 """The command line this process has been called with.""" 584 return self._proc.cmdline() 585 586 def status(self): 587 """The process current status as a STATUS_* constant.""" 588 try: 589 return self._proc.status() 590 except ZombieProcess: 591 return STATUS_ZOMBIE 592 593 def username(self): 594 """The name of the user that owns the process. 595 On UNIX this is calculated by using *real* process uid. 596 """ 597 if _POSIX: 598 if pwd is None: 599 # might happen if python was installed from sources 600 raise ImportError( 601 "requires pwd module shipped with standard python") 602 real_uid = self.uids().real 603 try: 604 return pwd.getpwuid(real_uid).pw_name 605 except KeyError: 606 # the uid can't be resolved by the system 607 return str(real_uid) 608 else: 609 return self._proc.username() 610 611 def create_time(self): 612 """The process creation time as a floating point number 613 expressed in seconds since the epoch, in UTC. 614 The return value is cached after first call. 615 """ 616 if self._create_time is None: 617 self._create_time = self._proc.create_time() 618 return self._create_time 619 620 def cwd(self): 621 """Process current working directory as an absolute path.""" 622 return self._proc.cwd() 623 624 def nice(self, value=None): 625 """Get or set process niceness (priority).""" 626 if value is None: 627 return self._proc.nice_get() 628 else: 629 if not self.is_running(): 630 raise NoSuchProcess(self.pid, self._name) 631 self._proc.nice_set(value) 632 633 if _POSIX: 634 635 def uids(self): 636 """Return process UIDs as a (real, effective, saved) 637 namedtuple. 638 """ 639 return self._proc.uids() 640 641 def gids(self): 642 """Return process GIDs as a (real, effective, saved) 643 namedtuple. 644 """ 645 return self._proc.gids() 646 647 def terminal(self): 648 """The terminal associated with this process, if any, 649 else None. 650 """ 651 return self._proc.terminal() 652 653 def num_fds(self): 654 """Return the number of file descriptors opened by this 655 process (POSIX only). 656 """ 657 return self._proc.num_fds() 658 659 # Linux, BSD and Windows only 660 if hasattr(_psplatform.Process, "io_counters"): 661 662 def io_counters(self): 663 """Return process I/O statistics as a 664 (read_count, write_count, read_bytes, write_bytes) 665 namedtuple. 666 Those are the number of read/write calls performed and the 667 amount of bytes read and written by the process. 668 """ 669 return self._proc.io_counters() 670 671 # Linux and Windows >= Vista only 672 if hasattr(_psplatform.Process, "ionice_get"): 673 674 def ionice(self, ioclass=None, value=None): 675 """Get or set process I/O niceness (priority). 676 677 On Linux 'ioclass' is one of the IOPRIO_CLASS_* constants. 678 'value' is a number which goes from 0 to 7. The higher the 679 value, the lower the I/O priority of the process. 680 681 On Windows only 'ioclass' is used and it can be set to 2 682 (normal), 1 (low) or 0 (very low). 683 684 Available on Linux and Windows > Vista only. 685 """ 686 if ioclass is None: 687 if value is not None: 688 raise ValueError("'ioclass' argument must be specified") 689 return self._proc.ionice_get() 690 else: 691 return self._proc.ionice_set(ioclass, value) 692 693 # Linux only 694 if hasattr(_psplatform.Process, "rlimit"): 695 696 def rlimit(self, resource, limits=None): 697 """Get or set process resource limits as a (soft, hard) 698 tuple. 699 700 'resource' is one of the RLIMIT_* constants. 701 'limits' is supposed to be a (soft, hard) tuple. 702 703 See "man prlimit" for further info. 704 Available on Linux only. 705 """ 706 if limits is None: 707 return self._proc.rlimit(resource) 708 else: 709 return self._proc.rlimit(resource, limits) 710 711 # Windows, Linux and BSD only 712 if hasattr(_psplatform.Process, "cpu_affinity_get"): 713 714 def cpu_affinity(self, cpus=None): 715 """Get or set process CPU affinity. 716 If specified 'cpus' must be a list of CPUs for which you 717 want to set the affinity (e.g. [0, 1]). 718 (Windows, Linux and BSD only). 719 """ 720 # Automatically remove duplicates both on get and 721 # set (for get it's not really necessary, it's 722 # just for extra safety). 723 if cpus is None: 724 return list(set(self._proc.cpu_affinity_get())) 725 else: 726 self._proc.cpu_affinity_set(list(set(cpus))) 727 728 if _WINDOWS: 729 730 def num_handles(self): 731 """Return the number of handles opened by this process 732 (Windows only). 733 """ 734 return self._proc.num_handles() 735 736 def num_ctx_switches(self): 737 """Return the number of voluntary and involuntary context 738 switches performed by this process. 739 """ 740 return self._proc.num_ctx_switches() 741 742 def num_threads(self): 743 """Return the number of threads used by this process.""" 744 return self._proc.num_threads() 745 746 def threads(self): 747 """Return threads opened by process as a list of 748 (id, user_time, system_time) namedtuples representing 749 thread id and thread CPU times (user/system). 750 """ 751 return self._proc.threads() 752 753 @_assert_pid_not_reused 754 def children(self, recursive=False): 755 """Return the children of this process as a list of Process 756 instances, pre-emptively checking whether PID has been reused. 757 If recursive is True return all the parent descendants. 758 759 Example (A == this process): 760 761 A ─┐ 762 │ 763 ├─ B (child) ─┐ 764 │ └─ X (grandchild) ─┐ 765 │ └─ Y (great grandchild) 766 ├─ C (child) 767 └─ D (child) 768 769 >>> import psutil 770 >>> p = psutil.Process() 771 >>> p.children() 772 B, C, D 773 >>> p.children(recursive=True) 774 B, X, Y, C, D 775 776 Note that in the example above if process X disappears 777 process Y won't be listed as the reference to process A 778 is lost. 779 """ 780 if hasattr(_psplatform, 'ppid_map'): 781 # Windows only: obtain a {pid:ppid, ...} dict for all running 782 # processes in one shot (faster). 783 ppid_map = _psplatform.ppid_map() 784 else: 785 ppid_map = None 786 787 ret = [] 788 if not recursive: 789 if ppid_map is None: 790 # 'slow' version, common to all platforms except Windows 791 for p in process_iter(): 792 try: 793 if p.ppid() == self.pid: 794 # if child happens to be older than its parent 795 # (self) it means child's PID has been reused 796 if self.create_time() <= p.create_time(): 797 ret.append(p) 798 except (NoSuchProcess, ZombieProcess): 799 pass 800 else: 801 # Windows only (faster) 802 for pid, ppid in ppid_map.items(): 803 if ppid == self.pid: 804 try: 805 child = Process(pid) 806 # if child happens to be older than its parent 807 # (self) it means child's PID has been reused 808 if self.create_time() <= child.create_time(): 809 ret.append(child) 810 except (NoSuchProcess, ZombieProcess): 811 pass 812 else: 813 # construct a dict where 'values' are all the processes 814 # having 'key' as their parent 815 table = collections.defaultdict(list) 816 if ppid_map is None: 817 for p in process_iter(): 818 try: 819 table[p.ppid()].append(p) 820 except (NoSuchProcess, ZombieProcess): 821 pass 822 else: 823 for pid, ppid in ppid_map.items(): 824 try: 825 p = Process(pid) 826 table[ppid].append(p) 827 except (NoSuchProcess, ZombieProcess): 828 pass 829 # At this point we have a mapping table where table[self.pid] 830 # are the current process' children. 831 # Below, we look for all descendants recursively, similarly 832 # to a recursive function call. 833 checkpids = [self.pid] 834 for pid in checkpids: 835 for child in table[pid]: 836 try: 837 # if child happens to be older than its parent 838 # (self) it means child's PID has been reused 839 intime = self.create_time() <= child.create_time() 840 except (NoSuchProcess, ZombieProcess): 841 pass 842 else: 843 if intime: 844 ret.append(child) 845 if child.pid not in checkpids: 846 checkpids.append(child.pid) 847 return ret 848 849 def cpu_percent(self, interval=None): 850 """Return a float representing the current process CPU 851 utilization as a percentage. 852 853 When interval is 0.0 or None (default) compares process times 854 to system CPU times elapsed since last call, returning 855 immediately (non-blocking). That means that the first time 856 this is called it will return a meaningful 0.0 value. 857 858 When interval is > 0.0 compares process times to system CPU 859 times elapsed before and after the interval (blocking). 860 861 In this case is recommended for accuracy that this function 862 be called with at least 0.1 seconds between calls. 863 864 Examples: 865 866 >>> import psutil 867 >>> p = psutil.Process(os.getpid()) 868 >>> # blocking 869 >>> p.cpu_percent(interval=1) 870 2.0 871 >>> # non-blocking (percentage since last call) 872 >>> p.cpu_percent(interval=None) 873 2.9 874 >>> 875 """ 876 blocking = interval is not None and interval > 0.0 877 num_cpus = cpu_count() 878 if _POSIX: 879 def timer(): 880 return _timer() * num_cpus 881 else: 882 def timer(): 883 return sum(cpu_times()) 884 if blocking: 885 st1 = timer() 886 pt1 = self._proc.cpu_times() 887 time.sleep(interval) 888 st2 = timer() 889 pt2 = self._proc.cpu_times() 890 else: 891 st1 = self._last_sys_cpu_times 892 pt1 = self._last_proc_cpu_times 893 st2 = timer() 894 pt2 = self._proc.cpu_times() 895 if st1 is None or pt1 is None: 896 self._last_sys_cpu_times = st2 897 self._last_proc_cpu_times = pt2 898 return 0.0 899 900 delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system) 901 delta_time = st2 - st1 902 # reset values for next call in case of interval == None 903 self._last_sys_cpu_times = st2 904 self._last_proc_cpu_times = pt2 905 906 try: 907 # The utilization split between all CPUs. 908 # Note: a percentage > 100 is legitimate as it can result 909 # from a process with multiple threads running on different 910 # CPU cores, see: 911 # http://stackoverflow.com/questions/1032357 912 # https://github.com/giampaolo/psutil/issues/474 913 overall_percent = ((delta_proc / delta_time) * 100) * num_cpus 914 except ZeroDivisionError: 915 # interval was too low 916 return 0.0 917 else: 918 return round(overall_percent, 1) 919 920 def cpu_times(self): 921 """Return a (user, system) namedtuple representing the 922 accumulated process time, in seconds. 923 This is the same as os.times() but per-process. 924 """ 925 return self._proc.cpu_times() 926 927 def memory_info(self): 928 """Return a tuple representing RSS (Resident Set Size) and VMS 929 (Virtual Memory Size) in bytes. 930 931 On UNIX RSS and VMS are the same values shown by 'ps'. 932 933 On Windows RSS and VMS refer to "Mem Usage" and "VM Size" 934 columns of taskmgr.exe. 935 """ 936 return self._proc.memory_info() 937 938 def memory_info_ex(self): 939 """Return a namedtuple with variable fields depending on the 940 platform representing extended memory information about 941 this process. All numbers are expressed in bytes. 942 """ 943 return self._proc.memory_info_ex() 944 945 def memory_percent(self): 946 """Compare physical system memory to process resident memory 947 (RSS) and calculate process memory utilization as a percentage. 948 """ 949 rss = self._proc.memory_info()[0] 950 # use cached value if available 951 total_phymem = _TOTAL_PHYMEM or virtual_memory().total 952 try: 953 return (rss / float(total_phymem)) * 100 954 except ZeroDivisionError: 955 return 0.0 956 957 def memory_maps(self, grouped=True): 958 """Return process' mapped memory regions as a list of namedtuples 959 whose fields are variable depending on the platform. 960 961 If 'grouped' is True the mapped regions with the same 'path' 962 are grouped together and the different memory fields are summed. 963 964 If 'grouped' is False every mapped region is shown as a single 965 entity and the namedtuple will also include the mapped region's 966 address space ('addr') and permission set ('perms'). 967 """ 968 it = self._proc.memory_maps() 969 if grouped: 970 d = {} 971 for tupl in it: 972 path = tupl[2] 973 nums = tupl[3:] 974 try: 975 d[path] = map(lambda x, y: x + y, d[path], nums) 976 except KeyError: 977 d[path] = nums 978 nt = _psplatform.pmmap_grouped 979 return [nt(path, *d[path]) for path in d] # NOQA 980 else: 981 nt = _psplatform.pmmap_ext 982 return [nt(*x) for x in it] 983 984 def open_files(self): 985 """Return files opened by process as a list of 986 (path, fd) namedtuples including the absolute file name 987 and file descriptor number. 988 """ 989 return self._proc.open_files() 990 991 def connections(self, kind='inet'): 992 """Return connections opened by process as a list of 993 (fd, family, type, laddr, raddr, status) namedtuples. 994 The 'kind' parameter filters for connections that match the 995 following criteria: 996 997 Kind Value Connections using 998 inet IPv4 and IPv6 999 inet4 IPv4 1000 inet6 IPv6 1001 tcp TCP 1002 tcp4 TCP over IPv4 1003 tcp6 TCP over IPv6 1004 udp UDP 1005 udp4 UDP over IPv4 1006 udp6 UDP over IPv6 1007 unix UNIX socket (both UDP and TCP protocols) 1008 all the sum of all the possible families and protocols 1009 """ 1010 return self._proc.connections(kind) 1011 1012 if _POSIX: 1013 def _send_signal(self, sig): 1014 if self.pid == 0: 1015 # see "man 2 kill" 1016 raise ValueError( 1017 "preventing sending signal to process with PID 0 as it " 1018 "would affect every process in the process group of the " 1019 "calling process (os.getpid()) instead of PID 0") 1020 try: 1021 os.kill(self.pid, sig) 1022 except OSError as err: 1023 if err.errno == errno.ESRCH: 1024 self._gone = True 1025 raise NoSuchProcess(self.pid, self._name) 1026 if err.errno == errno.EPERM: 1027 raise AccessDenied(self.pid, self._name) 1028 raise 1029 1030 @_assert_pid_not_reused 1031 def send_signal(self, sig): 1032 """Send a signal to process pre-emptively checking whether 1033 PID has been reused (see signal module constants) . 1034 On Windows only SIGTERM is valid and is treated as an alias 1035 for kill(). 1036 """ 1037 if _POSIX: 1038 self._send_signal(sig) 1039 else: 1040 if sig == signal.SIGTERM: 1041 self._proc.kill() 1042 else: 1043 raise ValueError("only SIGTERM is supported on Windows") 1044 1045 @_assert_pid_not_reused 1046 def suspend(self): 1047 """Suspend process execution with SIGSTOP pre-emptively checking 1048 whether PID has been reused. 1049 On Windows this has the effect ot suspending all process threads. 1050 """ 1051 if _POSIX: 1052 self._send_signal(signal.SIGSTOP) 1053 else: 1054 self._proc.suspend() 1055 1056 @_assert_pid_not_reused 1057 def resume(self): 1058 """Resume process execution with SIGCONT pre-emptively checking 1059 whether PID has been reused. 1060 On Windows this has the effect of resuming all process threads. 1061 """ 1062 if _POSIX: 1063 self._send_signal(signal.SIGCONT) 1064 else: 1065 self._proc.resume() 1066 1067 @_assert_pid_not_reused 1068 def terminate(self): 1069 """Terminate the process with SIGTERM pre-emptively checking 1070 whether PID has been reused. 1071 On Windows this is an alias for kill(). 1072 """ 1073 if _POSIX: 1074 self._send_signal(signal.SIGTERM) 1075 else: 1076 self._proc.kill() 1077 1078 @_assert_pid_not_reused 1079 def kill(self): 1080 """Kill the current process with SIGKILL pre-emptively checking 1081 whether PID has been reused. 1082 """ 1083 if _POSIX: 1084 self._send_signal(signal.SIGKILL) 1085 else: 1086 self._proc.kill() 1087 1088 def wait(self, timeout=None): 1089 """Wait for process to terminate and, if process is a children 1090 of os.getpid(), also return its exit code, else None. 1091 1092 If the process is already terminated immediately return None 1093 instead of raising NoSuchProcess. 1094 1095 If timeout (in seconds) is specified and process is still alive 1096 raise TimeoutExpired. 1097 1098 To wait for multiple Process(es) use psutil.wait_procs(). 1099 """ 1100 if timeout is not None and not timeout >= 0: 1101 raise ValueError("timeout must be a positive integer") 1102 return self._proc.wait(timeout) 1103 1104 1105# ===================================================================== 1106# --- Popen class 1107# ===================================================================== 1108 1109 1110class Popen(Process): 1111 """A more convenient interface to stdlib subprocess module. 1112 It starts a sub process and deals with it exactly as when using 1113 subprocess.Popen class but in addition also provides all the 1114 properties and methods of psutil.Process class as a unified 1115 interface: 1116 1117 >>> import psutil 1118 >>> from subprocess import PIPE 1119 >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE) 1120 >>> p.name() 1121 'python' 1122 >>> p.uids() 1123 user(real=1000, effective=1000, saved=1000) 1124 >>> p.username() 1125 'giampaolo' 1126 >>> p.communicate() 1127 ('hi\n', None) 1128 >>> p.terminate() 1129 >>> p.wait(timeout=2) 1130 0 1131 >>> 1132 1133 For method names common to both classes such as kill(), terminate() 1134 and wait(), psutil.Process implementation takes precedence. 1135 1136 Unlike subprocess.Popen this class pre-emptively checks wheter PID 1137 has been reused on send_signal(), terminate() and kill() so that 1138 you don't accidentally terminate another process, fixing 1139 http://bugs.python.org/issue6973. 1140 1141 For a complete documentation refer to: 1142 http://docs.python.org/library/subprocess.html 1143 """ 1144 1145 def __init__(self, *args, **kwargs): 1146 # Explicitly avoid to raise NoSuchProcess in case the process 1147 # spawned by subprocess.Popen terminates too quickly, see: 1148 # https://github.com/giampaolo/psutil/issues/193 1149 self.__subproc = subprocess.Popen(*args, **kwargs) 1150 self._init(self.__subproc.pid, _ignore_nsp=True) 1151 1152 def __dir__(self): 1153 return sorted(set(dir(Popen) + dir(subprocess.Popen))) 1154 1155 def __getattribute__(self, name): 1156 try: 1157 return object.__getattribute__(self, name) 1158 except AttributeError: 1159 try: 1160 return object.__getattribute__(self.__subproc, name) 1161 except AttributeError: 1162 raise AttributeError("%s instance has no attribute '%s'" 1163 % (self.__class__.__name__, name)) 1164 1165 def wait(self, timeout=None): 1166 if self.__subproc.returncode is not None: 1167 return self.__subproc.returncode 1168 ret = super(Popen, self).wait(timeout) 1169 self.__subproc.returncode = ret 1170 return ret 1171 1172 1173# ===================================================================== 1174# --- system processes related functions 1175# ===================================================================== 1176 1177 1178def pids(): 1179 """Return a list of current running PIDs.""" 1180 return _psplatform.pids() 1181 1182 1183def pid_exists(pid): 1184 """Return True if given PID exists in the current process list. 1185 This is faster than doing "pid in psutil.pids()" and 1186 should be preferred. 1187 """ 1188 if pid < 0: 1189 return False 1190 elif pid == 0 and _POSIX: 1191 # On POSIX we use os.kill() to determine PID existence. 1192 # According to "man 2 kill" PID 0 has a special meaning 1193 # though: it refers to <<every process in the process 1194 # group of the calling process>> and that is not we want 1195 # to do here. 1196 return pid in pids() 1197 else: 1198 return _psplatform.pid_exists(pid) 1199 1200 1201_pmap = {} 1202 1203 1204def process_iter(): 1205 """Return a generator yielding a Process instance for all 1206 running processes. 1207 1208 Every new Process instance is only created once and then cached 1209 into an internal table which is updated every time this is used. 1210 1211 Cached Process instances are checked for identity so that you're 1212 safe in case a PID has been reused by another process, in which 1213 case the cached instance is updated. 1214 1215 The sorting order in which processes are yielded is based on 1216 their PIDs. 1217 """ 1218 def add(pid): 1219 proc = Process(pid) 1220 _pmap[proc.pid] = proc 1221 return proc 1222 1223 def remove(pid): 1224 _pmap.pop(pid, None) 1225 1226 a = set(pids()) 1227 b = set(_pmap.keys()) 1228 new_pids = a - b 1229 gone_pids = b - a 1230 1231 for pid in gone_pids: 1232 remove(pid) 1233 for pid, proc in sorted(list(_pmap.items()) + 1234 list(dict.fromkeys(new_pids).items())): 1235 try: 1236 if proc is None: # new process 1237 yield add(pid) 1238 else: 1239 # use is_running() to check whether PID has been reused by 1240 # another process in which case yield a new Process instance 1241 if proc.is_running(): 1242 yield proc 1243 else: 1244 yield add(pid) 1245 except NoSuchProcess: 1246 remove(pid) 1247 except AccessDenied: 1248 # Process creation time can't be determined hence there's 1249 # no way to tell whether the pid of the cached process 1250 # has been reused. Just return the cached version. 1251 yield proc 1252 1253 1254def wait_procs(procs, timeout=None, callback=None): 1255 """Convenience function which waits for a list of processes to 1256 terminate. 1257 1258 Return a (gone, alive) tuple indicating which processes 1259 are gone and which ones are still alive. 1260 1261 The gone ones will have a new 'returncode' attribute indicating 1262 process exit status (may be None). 1263 1264 'callback' is a function which gets called every time a process 1265 terminates (a Process instance is passed as callback argument). 1266 1267 Function will return as soon as all processes terminate or when 1268 timeout occurs. 1269 1270 Typical use case is: 1271 1272 - send SIGTERM to a list of processes 1273 - give them some time to terminate 1274 - send SIGKILL to those ones which are still alive 1275 1276 Example: 1277 1278 >>> def on_terminate(proc): 1279 ... print("process {} terminated".format(proc)) 1280 ... 1281 >>> for p in procs: 1282 ... p.terminate() 1283 ... 1284 >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate) 1285 >>> for p in alive: 1286 ... p.kill() 1287 """ 1288 def check_gone(proc, timeout): 1289 try: 1290 returncode = proc.wait(timeout=timeout) 1291 except TimeoutExpired: 1292 pass 1293 else: 1294 if returncode is not None or not proc.is_running(): 1295 proc.returncode = returncode 1296 gone.add(proc) 1297 if callback is not None: 1298 callback(proc) 1299 1300 if timeout is not None and not timeout >= 0: 1301 msg = "timeout must be a positive integer, got %s" % timeout 1302 raise ValueError(msg) 1303 gone = set() 1304 alive = set(procs) 1305 if callback is not None and not callable(callback): 1306 raise TypeError("callback %r is not a callable" % callable) 1307 if timeout is not None: 1308 deadline = _timer() + timeout 1309 1310 while alive: 1311 if timeout is not None and timeout <= 0: 1312 break 1313 for proc in alive: 1314 # Make sure that every complete iteration (all processes) 1315 # will last max 1 sec. 1316 # We do this because we don't want to wait too long on a 1317 # single process: in case it terminates too late other 1318 # processes may disappear in the meantime and their PID 1319 # reused. 1320 max_timeout = 1.0 / len(alive) 1321 if timeout is not None: 1322 timeout = min((deadline - _timer()), max_timeout) 1323 if timeout <= 0: 1324 break 1325 check_gone(proc, timeout) 1326 else: 1327 check_gone(proc, max_timeout) 1328 alive = alive - gone 1329 1330 if alive: 1331 # Last attempt over processes survived so far. 1332 # timeout == 0 won't make this function wait any further. 1333 for proc in alive: 1334 check_gone(proc, 0) 1335 alive = alive - gone 1336 1337 return (list(gone), list(alive)) 1338 1339 1340# ===================================================================== 1341# --- CPU related functions 1342# ===================================================================== 1343 1344 1345@memoize 1346def cpu_count(logical=True): 1347 """Return the number of logical CPUs in the system (same as 1348 os.cpu_count() in Python 3.4). 1349 1350 If logical is False return the number of physical cores only 1351 (e.g. hyper thread CPUs are excluded). 1352 1353 Return None if undetermined. 1354 1355 The return value is cached after first call. 1356 If desired cache can be cleared like this: 1357 1358 >>> psutil.cpu_count.cache_clear() 1359 """ 1360 if logical: 1361 return _psplatform.cpu_count_logical() 1362 else: 1363 return _psplatform.cpu_count_physical() 1364 1365 1366def cpu_times(percpu=False): 1367 """Return system-wide CPU times as a namedtuple. 1368 Every CPU time represents the seconds the CPU has spent in the given mode. 1369 The namedtuple's fields availability varies depending on the platform: 1370 - user 1371 - system 1372 - idle 1373 - nice (UNIX) 1374 - iowait (Linux) 1375 - irq (Linux, FreeBSD) 1376 - softirq (Linux) 1377 - steal (Linux >= 2.6.11) 1378 - guest (Linux >= 2.6.24) 1379 - guest_nice (Linux >= 3.2.0) 1380 1381 When percpu is True return a list of namedtuples for each CPU. 1382 First element of the list refers to first CPU, second element 1383 to second CPU and so on. 1384 The order of the list is consistent across calls. 1385 """ 1386 if not percpu: 1387 return _psplatform.cpu_times() 1388 else: 1389 return _psplatform.per_cpu_times() 1390 1391 1392_last_cpu_times = cpu_times() 1393_last_per_cpu_times = cpu_times(percpu=True) 1394 1395 1396def cpu_percent(interval=None, percpu=False): 1397 """Return a float representing the current system-wide CPU 1398 utilization as a percentage. 1399 1400 When interval is > 0.0 compares system CPU times elapsed before 1401 and after the interval (blocking). 1402 1403 When interval is 0.0 or None compares system CPU times elapsed 1404 since last call or module import, returning immediately (non 1405 blocking). That means the first time this is called it will 1406 return a meaningless 0.0 value which you should ignore. 1407 In this case is recommended for accuracy that this function be 1408 called with at least 0.1 seconds between calls. 1409 1410 When percpu is True returns a list of floats representing the 1411 utilization as a percentage for each CPU. 1412 First element of the list refers to first CPU, second element 1413 to second CPU and so on. 1414 The order of the list is consistent across calls. 1415 1416 Examples: 1417 1418 >>> # blocking, system-wide 1419 >>> psutil.cpu_percent(interval=1) 1420 2.0 1421 >>> 1422 >>> # blocking, per-cpu 1423 >>> psutil.cpu_percent(interval=1, percpu=True) 1424 [2.0, 1.0] 1425 >>> 1426 >>> # non-blocking (percentage since last call) 1427 >>> psutil.cpu_percent(interval=None) 1428 2.9 1429 >>> 1430 """ 1431 global _last_cpu_times 1432 global _last_per_cpu_times 1433 blocking = interval is not None and interval > 0.0 1434 1435 def calculate(t1, t2): 1436 t1_all = sum(t1) 1437 t1_busy = t1_all - t1.idle 1438 1439 t2_all = sum(t2) 1440 t2_busy = t2_all - t2.idle 1441 1442 # this usually indicates a float precision issue 1443 if t2_busy <= t1_busy: 1444 return 0.0 1445 1446 busy_delta = t2_busy - t1_busy 1447 all_delta = t2_all - t1_all 1448 busy_perc = (busy_delta / all_delta) * 100 1449 return round(busy_perc, 1) 1450 1451 # system-wide usage 1452 if not percpu: 1453 if blocking: 1454 t1 = cpu_times() 1455 time.sleep(interval) 1456 else: 1457 t1 = _last_cpu_times 1458 _last_cpu_times = cpu_times() 1459 return calculate(t1, _last_cpu_times) 1460 # per-cpu usage 1461 else: 1462 ret = [] 1463 if blocking: 1464 tot1 = cpu_times(percpu=True) 1465 time.sleep(interval) 1466 else: 1467 tot1 = _last_per_cpu_times 1468 _last_per_cpu_times = cpu_times(percpu=True) 1469 for t1, t2 in zip(tot1, _last_per_cpu_times): 1470 ret.append(calculate(t1, t2)) 1471 return ret 1472 1473 1474# Use separate global vars for cpu_times_percent() so that it's 1475# independent from cpu_percent() and they can both be used within 1476# the same program. 1477_last_cpu_times_2 = _last_cpu_times 1478_last_per_cpu_times_2 = _last_per_cpu_times 1479 1480 1481def cpu_times_percent(interval=None, percpu=False): 1482 """Same as cpu_percent() but provides utilization percentages 1483 for each specific CPU time as is returned by cpu_times(). 1484 For instance, on Linux we'll get: 1485 1486 >>> cpu_times_percent() 1487 cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0, 1488 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) 1489 >>> 1490 1491 interval and percpu arguments have the same meaning as in 1492 cpu_percent(). 1493 """ 1494 global _last_cpu_times_2 1495 global _last_per_cpu_times_2 1496 blocking = interval is not None and interval > 0.0 1497 1498 def calculate(t1, t2): 1499 nums = [] 1500 all_delta = sum(t2) - sum(t1) 1501 for field in t1._fields: 1502 field_delta = getattr(t2, field) - getattr(t1, field) 1503 try: 1504 field_perc = (100 * field_delta) / all_delta 1505 except ZeroDivisionError: 1506 field_perc = 0.0 1507 field_perc = round(field_perc, 1) 1508 # CPU times are always supposed to increase over time 1509 # or at least remain the same and that's because time 1510 # cannot go backwards. 1511 # Surprisingly sometimes this might not be the case (at 1512 # least on Windows and Linux), see: 1513 # https://github.com/giampaolo/psutil/issues/392 1514 # https://github.com/giampaolo/psutil/issues/645 1515 # I really don't know what to do about that except 1516 # forcing the value to 0 or 100. 1517 if field_perc > 100.0: 1518 field_perc = 100.0 1519 # `<=` because `-0.0 == 0.0` evaluates to True 1520 elif field_perc <= 0.0: 1521 field_perc = 0.0 1522 nums.append(field_perc) 1523 return _psplatform.scputimes(*nums) 1524 1525 # system-wide usage 1526 if not percpu: 1527 if blocking: 1528 t1 = cpu_times() 1529 time.sleep(interval) 1530 else: 1531 t1 = _last_cpu_times_2 1532 _last_cpu_times_2 = cpu_times() 1533 return calculate(t1, _last_cpu_times_2) 1534 # per-cpu usage 1535 else: 1536 ret = [] 1537 if blocking: 1538 tot1 = cpu_times(percpu=True) 1539 time.sleep(interval) 1540 else: 1541 tot1 = _last_per_cpu_times_2 1542 _last_per_cpu_times_2 = cpu_times(percpu=True) 1543 for t1, t2 in zip(tot1, _last_per_cpu_times_2): 1544 ret.append(calculate(t1, t2)) 1545 return ret 1546 1547 1548# ===================================================================== 1549# --- system memory related functions 1550# ===================================================================== 1551 1552 1553def virtual_memory(): 1554 """Return statistics about system memory usage as a namedtuple 1555 including the following fields, expressed in bytes: 1556 1557 - total: 1558 total physical memory available. 1559 1560 - available: 1561 the actual amount of available memory that can be given 1562 instantly to processes that request more memory in bytes; this 1563 is calculated by summing different memory values depending on 1564 the platform (e.g. free + buffers + cached on Linux) and it is 1565 supposed to be used to monitor actual memory usage in a cross 1566 platform fashion. 1567 1568 - percent: 1569 the percentage usage calculated as (total - available) / total * 100 1570 1571 - used: 1572 memory used, calculated differently depending on the platform and 1573 designed for informational purposes only: 1574 OSX: active + inactive + wired 1575 BSD: active + wired + cached 1576 LINUX: total - free 1577 1578 - free: 1579 memory not being used at all (zeroed) that is readily available; 1580 note that this doesn't reflect the actual memory available 1581 (use 'available' instead) 1582 1583 Platform-specific fields: 1584 1585 - active (UNIX): 1586 memory currently in use or very recently used, and so it is in RAM. 1587 1588 - inactive (UNIX): 1589 memory that is marked as not used. 1590 1591 - buffers (BSD, Linux): 1592 cache for things like file system metadata. 1593 1594 - cached (BSD, OSX): 1595 cache for various things. 1596 1597 - wired (OSX, BSD): 1598 memory that is marked to always stay in RAM. It is never moved to disk. 1599 1600 - shared (BSD): 1601 memory that may be simultaneously accessed by multiple processes. 1602 1603 The sum of 'used' and 'available' does not necessarily equal total. 1604 On Windows 'available' and 'free' are the same. 1605 """ 1606 global _TOTAL_PHYMEM 1607 ret = _psplatform.virtual_memory() 1608 # cached for later use in Process.memory_percent() 1609 _TOTAL_PHYMEM = ret.total 1610 return ret 1611 1612 1613def swap_memory(): 1614 """Return system swap memory statistics as a namedtuple including 1615 the following fields: 1616 1617 - total: total swap memory in bytes 1618 - used: used swap memory in bytes 1619 - free: free swap memory in bytes 1620 - percent: the percentage usage 1621 - sin: no. of bytes the system has swapped in from disk (cumulative) 1622 - sout: no. of bytes the system has swapped out from disk (cumulative) 1623 1624 'sin' and 'sout' on Windows are meaningless and always set to 0. 1625 """ 1626 return _psplatform.swap_memory() 1627 1628 1629# ===================================================================== 1630# --- disks/paritions related functions 1631# ===================================================================== 1632 1633 1634def disk_usage(path): 1635 """Return disk usage statistics about the given path as a namedtuple 1636 including total, used and free space expressed in bytes plus the 1637 percentage usage. 1638 """ 1639 return _psplatform.disk_usage(path) 1640 1641 1642def disk_partitions(all=False): 1643 """Return mounted partitions as a list of 1644 (device, mountpoint, fstype, opts) namedtuple. 1645 'opts' field is a raw string separated by commas indicating mount 1646 options which may vary depending on the platform. 1647 1648 If "all" parameter is False return physical devices only and ignore 1649 all others. 1650 """ 1651 return _psplatform.disk_partitions(all) 1652 1653 1654def disk_io_counters(perdisk=False): 1655 """Return system disk I/O statistics as a namedtuple including 1656 the following fields: 1657 1658 - read_count: number of reads 1659 - write_count: number of writes 1660 - read_bytes: number of bytes read 1661 - write_bytes: number of bytes written 1662 - read_time: time spent reading from disk (in milliseconds) 1663 - write_time: time spent writing to disk (in milliseconds) 1664 1665 If perdisk is True return the same information for every 1666 physical disk installed on the system as a dictionary 1667 with partition names as the keys and the namedtuple 1668 described above as the values. 1669 1670 On recent Windows versions 'diskperf -y' command may need to be 1671 executed first otherwise this function won't find any disk. 1672 """ 1673 rawdict = _psplatform.disk_io_counters() 1674 if not rawdict: 1675 raise RuntimeError("couldn't find any physical disk") 1676 if perdisk: 1677 for disk, fields in rawdict.items(): 1678 rawdict[disk] = _common.sdiskio(*fields) 1679 return rawdict 1680 else: 1681 return _common.sdiskio(*[sum(x) for x in zip(*rawdict.values())]) 1682 1683 1684# ===================================================================== 1685# --- network related functions 1686# ===================================================================== 1687 1688 1689def net_io_counters(pernic=False): 1690 """Return network I/O statistics as a namedtuple including 1691 the following fields: 1692 1693 - bytes_sent: number of bytes sent 1694 - bytes_recv: number of bytes received 1695 - packets_sent: number of packets sent 1696 - packets_recv: number of packets received 1697 - errin: total number of errors while receiving 1698 - errout: total number of errors while sending 1699 - dropin: total number of incoming packets which were dropped 1700 - dropout: total number of outgoing packets which were dropped 1701 (always 0 on OSX and BSD) 1702 1703 If pernic is True return the same information for every 1704 network interface installed on the system as a dictionary 1705 with network interface names as the keys and the namedtuple 1706 described above as the values. 1707 """ 1708 rawdict = _psplatform.net_io_counters() 1709 if not rawdict: 1710 raise RuntimeError("couldn't find any network interface") 1711 if pernic: 1712 for nic, fields in rawdict.items(): 1713 rawdict[nic] = _common.snetio(*fields) 1714 return rawdict 1715 else: 1716 return _common.snetio(*[sum(x) for x in zip(*rawdict.values())]) 1717 1718 1719def net_connections(kind='inet'): 1720 """Return system-wide connections as a list of 1721 (fd, family, type, laddr, raddr, status, pid) namedtuples. 1722 In case of limited privileges 'fd' and 'pid' may be set to -1 1723 and None respectively. 1724 The 'kind' parameter filters for connections that fit the 1725 following criteria: 1726 1727 Kind Value Connections using 1728 inet IPv4 and IPv6 1729 inet4 IPv4 1730 inet6 IPv6 1731 tcp TCP 1732 tcp4 TCP over IPv4 1733 tcp6 TCP over IPv6 1734 udp UDP 1735 udp4 UDP over IPv4 1736 udp6 UDP over IPv6 1737 unix UNIX socket (both UDP and TCP protocols) 1738 all the sum of all the possible families and protocols 1739 1740 On OSX this function requires root privileges. 1741 """ 1742 return _psplatform.net_connections(kind) 1743 1744 1745def net_if_addrs(): 1746 """Return the addresses associated to each NIC (network interface 1747 card) installed on the system as a dictionary whose keys are the 1748 NIC names and value is a list of namedtuples for each address 1749 assigned to the NIC. Each namedtuple includes 4 fields: 1750 1751 - family 1752 - address 1753 - netmask 1754 - broadcast 1755 1756 'family' can be either socket.AF_INET, socket.AF_INET6 or 1757 psutil.AF_LINK, which refers to a MAC address. 1758 'address' is the primary address, 'netmask' and 'broadcast' 1759 may be None. 1760 Note: you can have more than one address of the same family 1761 associated with each interface. 1762 """ 1763 has_enums = sys.version_info >= (3, 4) 1764 if has_enums: 1765 import socket 1766 rawlist = _psplatform.net_if_addrs() 1767 rawlist.sort(key=lambda x: x[1]) # sort by family 1768 ret = collections.defaultdict(list) 1769 for name, fam, addr, mask, broadcast in rawlist: 1770 if has_enums: 1771 try: 1772 fam = socket.AddressFamily(fam) 1773 except ValueError: 1774 if os.name == 'nt' and fam == -1: 1775 fam = _psplatform.AF_LINK 1776 elif (hasattr(_psplatform, "AF_LINK") and 1777 _psplatform.AF_LINK == fam): 1778 # Linux defines AF_LINK as an alias for AF_PACKET. 1779 # We re-set the family here so that repr(family) 1780 # will show AF_LINK rather than AF_PACKET 1781 fam = _psplatform.AF_LINK 1782 ret[name].append(_common.snic(fam, addr, mask, broadcast)) 1783 return dict(ret) 1784 1785 1786def net_if_stats(): 1787 """Return information about each NIC (network interface card) 1788 installed on the system as a dictionary whose keys are the 1789 NIC names and value is a namedtuple with the following fields: 1790 1791 - isup: whether the interface is up (bool) 1792 - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or 1793 NIC_DUPLEX_UNKNOWN 1794 - speed: the NIC speed expressed in mega bits (MB); if it can't 1795 be determined (e.g. 'localhost') it will be set to 0. 1796 - mtu: the maximum transmission unit expressed in bytes. 1797 """ 1798 return _psplatform.net_if_stats() 1799 1800 1801# ===================================================================== 1802# --- other system related functions 1803# ===================================================================== 1804 1805 1806def boot_time(): 1807 """Return the system boot time expressed in seconds since the epoch.""" 1808 # Note: we are not caching this because it is subject to 1809 # system clock updates. 1810 return _psplatform.boot_time() 1811 1812 1813def users(): 1814 """Return users currently connected on the system as a list of 1815 namedtuples including the following fields. 1816 1817 - user: the name of the user 1818 - terminal: the tty or pseudo-tty associated with the user, if any. 1819 - host: the host name associated with the entry, if any. 1820 - started: the creation time as a floating point number expressed in 1821 seconds since the epoch. 1822 """ 1823 return _psplatform.users() 1824 1825 1826def test(): 1827 """List info of all currently running processes emulating ps aux 1828 output. 1829 """ 1830 import datetime 1831 1832 today_day = datetime.date.today() 1833 templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s" 1834 attrs = ['pid', 'cpu_percent', 'memory_percent', 'name', 'cpu_times', 1835 'create_time', 'memory_info'] 1836 if _POSIX: 1837 attrs.append('uids') 1838 attrs.append('terminal') 1839 print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", 1840 "START", "TIME", "COMMAND")) 1841 for p in process_iter(): 1842 try: 1843 pinfo = p.as_dict(attrs, ad_value='') 1844 except NoSuchProcess: 1845 pass 1846 else: 1847 if pinfo['create_time']: 1848 ctime = datetime.datetime.fromtimestamp(pinfo['create_time']) 1849 if ctime.date() == today_day: 1850 ctime = ctime.strftime("%H:%M") 1851 else: 1852 ctime = ctime.strftime("%b%d") 1853 else: 1854 ctime = '' 1855 cputime = time.strftime("%M:%S", 1856 time.localtime(sum(pinfo['cpu_times']))) 1857 try: 1858 user = p.username() 1859 except Error: 1860 user = '' 1861 if _WINDOWS and '\\' in user: 1862 user = user.split('\\')[1] 1863 vms = pinfo['memory_info'] and \ 1864 int(pinfo['memory_info'].vms / 1024) or '?' 1865 rss = pinfo['memory_info'] and \ 1866 int(pinfo['memory_info'].rss / 1024) or '?' 1867 memp = pinfo['memory_percent'] and \ 1868 round(pinfo['memory_percent'], 1) or '?' 1869 print(templ % ( 1870 user[:10], 1871 pinfo['pid'], 1872 pinfo['cpu_percent'], 1873 memp, 1874 vms, 1875 rss, 1876 pinfo.get('terminal', '') or '?', 1877 ctime, 1878 cputime, 1879 pinfo['name'].strip() or '?')) 1880 1881 1882del memoize, division 1883if sys.version_info < (3, 0): 1884 del num 1885 1886if __name__ == "__main__": 1887 test() 1888