Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py2493 linesDownload Raw Back to psutil
1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""psutil is a cross-platform library for retrieving information on
8running processes and system utilization (CPU, memory, disks, network,
9sensors) in Python. Supported platforms:
10
11 - Linux
12 - Windows
13 - macOS
14 - FreeBSD
15 - OpenBSD
16 - NetBSD
17 - Sun Solaris
18 - AIX
19
20Works with Python versions 2.7 and 3.6+.
21"""
22
23from __future__ import division
24
25import collections
26import contextlib
27import datetime
28import functools
29import os
30import signal
31import subprocess
32import sys
33import threading
34import time
35
36
37try:
38    import pwd
39except ImportError:
40    pwd = None
41
42from . import _common
43from ._common import AIX
44from ._common import BSD
45from ._common import CONN_CLOSE
46from ._common import CONN_CLOSE_WAIT
47from ._common import CONN_CLOSING
48from ._common import CONN_ESTABLISHED
49from ._common import CONN_FIN_WAIT1
50from ._common import CONN_FIN_WAIT2
51from ._common import CONN_LAST_ACK
52from ._common import CONN_LISTEN
53from ._common import CONN_NONE
54from ._common import CONN_SYN_RECV
55from ._common import CONN_SYN_SENT
56from ._common import CONN_TIME_WAIT
57from ._common import FREEBSD  # NOQA
58from ._common import LINUX
59from ._common import MACOS
60from ._common import NETBSD  # NOQA
61from ._common import NIC_DUPLEX_FULL
62from ._common import NIC_DUPLEX_HALF
63from ._common import NIC_DUPLEX_UNKNOWN
64from ._common import OPENBSD  # NOQA
65from ._common import OSX  # deprecated alias
66from ._common import POSIX  # NOQA
67from ._common import POWER_TIME_UNKNOWN
68from ._common import POWER_TIME_UNLIMITED
69from ._common import STATUS_DEAD
70from ._common import STATUS_DISK_SLEEP
71from ._common import STATUS_IDLE
72from ._common import STATUS_LOCKED
73from ._common import STATUS_PARKED
74from ._common import STATUS_RUNNING
75from ._common import STATUS_SLEEPING
76from ._common import STATUS_STOPPED
77from ._common import STATUS_TRACING_STOP
78from ._common import STATUS_WAITING
79from ._common import STATUS_WAKING
80from ._common import STATUS_ZOMBIE
81from ._common import SUNOS
82from ._common import WINDOWS
83from ._common import AccessDenied
84from ._common import Error
85from ._common import NoSuchProcess
86from ._common import TimeoutExpired
87from ._common import ZombieProcess
88from ._common import memoize_when_activated
89from ._common import wrap_numbers as _wrap_numbers
90from ._compat import PY3 as _PY3
91from ._compat import PermissionError
92from ._compat import ProcessLookupError
93from ._compat import SubprocessTimeoutExpired as _SubprocessTimeoutExpired
94from ._compat import long
95
96
97if LINUX:
98    # This is public API and it will be retrieved from _pslinux.py
99    # via sys.modules.
100    PROCFS_PATH = "/proc"
101
102    from . import _pslinux as _psplatform
103    from ._pslinux import IOPRIO_CLASS_BE  # NOQA
104    from ._pslinux import IOPRIO_CLASS_IDLE  # NOQA
105    from ._pslinux import IOPRIO_CLASS_NONE  # NOQA
106    from ._pslinux import IOPRIO_CLASS_RT  # NOQA
107
108elif WINDOWS:
109    from . import _pswindows as _psplatform
110    from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS  # NOQA
111    from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS  # NOQA
112    from ._psutil_windows import HIGH_PRIORITY_CLASS  # NOQA
113    from ._psutil_windows import IDLE_PRIORITY_CLASS  # NOQA
114    from ._psutil_windows import NORMAL_PRIORITY_CLASS  # NOQA
115    from ._psutil_windows import REALTIME_PRIORITY_CLASS  # NOQA
116    from ._pswindows import CONN_DELETE_TCB  # NOQA
117    from ._pswindows import IOPRIO_HIGH  # NOQA
118    from ._pswindows import IOPRIO_LOW  # NOQA
119    from ._pswindows import IOPRIO_NORMAL  # NOQA
120    from ._pswindows import IOPRIO_VERYLOW  # NOQA
121
122elif MACOS:
123    from . import _psosx as _psplatform
124
125elif BSD:
126    from . import _psbsd as _psplatform
127
128elif SUNOS:
129    from . import _pssunos as _psplatform
130    from ._pssunos import CONN_BOUND  # NOQA
131    from ._pssunos import CONN_IDLE  # NOQA
132
133    # This is public writable API which is read from _pslinux.py and
134    # _pssunos.py via sys.modules.
135    PROCFS_PATH = "/proc"
136
137elif AIX:
138    from . import _psaix as _psplatform
139
140    # This is public API and it will be retrieved from _pslinux.py
141    # via sys.modules.
142    PROCFS_PATH = "/proc"
143
144else:  # pragma: no cover
145    raise NotImplementedError('platform %s is not supported' % sys.platform)
146
147
148# fmt: off
149__all__ = [
150    # exceptions
151    "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied",
152    "TimeoutExpired",
153
154    # constants
155    "version_info", "__version__",
156
157    "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
158    "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
159    "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
160    "STATUS_PARKED",
161
162    "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
163    "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
164    "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE",
165    # "CONN_IDLE", "CONN_BOUND",
166
167    "AF_LINK",
168
169    "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN",
170
171    "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
172
173    "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
174    "SUNOS", "WINDOWS", "AIX",
175
176    # "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA",
177    # "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE",
178    # "RLIMIT_NPROC", "RLIMIT_RSS", "RLIMIT_STACK", "RLIMIT_MSGQUEUE",
179    # "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIMIT_SIGPENDING",
180
181    # classes
182    "Process", "Popen",
183
184    # functions
185    "pid_exists", "pids", "process_iter", "wait_procs",             # proc
186    "virtual_memory", "swap_memory",                                # memory
187    "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count",   # cpu
188    "cpu_stats",  # "cpu_freq", "getloadavg"
189    "net_io_counters", "net_connections", "net_if_addrs",           # network
190    "net_if_stats",
191    "disk_io_counters", "disk_partitions", "disk_usage",            # disk
192    # "sensors_temperatures", "sensors_battery", "sensors_fans"     # sensors
193    "users", "boot_time",                                           # others
194]
195# fmt: on
196
197
198__all__.extend(_psplatform.__extra__all__)
199
200# Linux, FreeBSD
201if hasattr(_psplatform.Process, "rlimit"):
202    # Populate global namespace with RLIM* constants.
203    from . import _psutil_posix
204
205    _globals = globals()
206    _name = None
207    for _name in dir(_psutil_posix):
208        if _name.startswith('RLIM') and _name.isupper():
209            _globals[_name] = getattr(_psutil_posix, _name)
210            __all__.append(_name)
211    del _globals, _name
212
213AF_LINK = _psplatform.AF_LINK
214
215__author__ = "Giampaolo Rodola'"
216__version__ = "5.9.8"
217version_info = tuple([int(num) for num in __version__.split('.')])
218
219_timer = getattr(time, 'monotonic', time.time)
220_TOTAL_PHYMEM = None
221_LOWEST_PID = None
222_SENTINEL = object()
223
224# Sanity check in case the user messed up with psutil installation
225# or did something weird with sys.path. In this case we might end
226# up importing a python module using a C extension module which
227# was compiled for a different version of psutil.
228# We want to prevent that by failing sooner rather than later.
229# See: https://github.com/giampaolo/psutil/issues/564
230if int(__version__.replace('.', '')) != getattr(
231    _psplatform.cext, 'version', None
232):
233    msg = "version conflict: %r C extension " % _psplatform.cext.__file__
234    msg += "module was built for another version of psutil"
235    if hasattr(_psplatform.cext, 'version'):
236        msg += " (%s instead of %s)" % (
237            '.'.join([x for x in str(_psplatform.cext.version)]),
238            __version__,
239        )
240    else:
241        msg += " (different than %s)" % __version__
242    msg += "; you may try to 'pip uninstall psutil', manually remove %s" % (
243        getattr(
244            _psplatform.cext,
245            "__file__",
246            "the existing psutil install directory",
247        )
248    )
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:  # pragma: no cover
262
263    def _ppid_map():
264        """Return a {pid: ppid, ...} dict for all running processes in
265        one shot. Used to speed up Process.children().
266        """
267        ret = {}
268        for pid in pids():
269            try:
270                ret[pid] = _psplatform.Process(pid).ppid()
271            except (NoSuchProcess, ZombieProcess):
272                pass
273        return ret
274
275
276def _pprint_secs(secs):
277    """Format seconds in a human readable form."""
278    now = time.time()
279    secs_ago = int(now - secs)
280    fmt = "%H:%M:%S" if secs_ago < 60 * 60 * 24 else "%Y-%m-%d %H:%M:%S"
281    return datetime.datetime.fromtimestamp(secs).strftime(fmt)
282
283
284# =====================================================================
285# --- Process class
286# =====================================================================
287
288
289class Process(object):  # noqa: UP004
290    """Represents an OS process with the given PID.
291    If PID is omitted current process PID (os.getpid()) is used.
292    Raise NoSuchProcess if PID does not exist.
293
294    Note that most of the methods of this class do not make sure
295    the PID of the process being queried has been reused over time.
296    That means you might end up retrieving an information referring
297    to another process in case the original one this instance
298    refers to is gone in the meantime.
299
300    The only exceptions for which process identity is pre-emptively
301    checked and guaranteed are:
302
303     - parent()
304     - children()
305     - nice() (set)
306     - ionice() (set)
307     - rlimit() (set)
308     - cpu_affinity (set)
309     - suspend()
310     - resume()
311     - send_signal()
312     - terminate()
313     - kill()
314
315    To prevent this problem for all other methods you can:
316     - use is_running() before querying the process
317     - if you're continuously iterating over a set of Process
318       instances use process_iter() which pre-emptively checks
319       process identity for every yielded instance
320    """
321
322    def __init__(self, pid=None):
323        self._init(pid)
324
325    def _init(self, pid, _ignore_nsp=False):
326        if pid is None:
327            pid = os.getpid()
328        else:
329            if not _PY3 and not isinstance(pid, (int, long)):
330                msg = "pid must be an integer (got %r)" % pid
331                raise TypeError(msg)
332            if pid < 0:
333                msg = "pid must be a positive integer (got %s)" % pid
334                raise ValueError(msg)
335            try:
336                _psplatform.cext.check_pid_range(pid)
337            except OverflowError:
338                msg = "process PID out of range (got %s)" % pid
339                raise NoSuchProcess(pid, msg=msg)
340
341        self._pid = pid
342        self._name = None
343        self._exe = None
344        self._create_time = None
345        self._gone = False
346        self._pid_reused = False
347        self._hash = None
348        self._lock = threading.RLock()
349        # used for caching on Windows only (on POSIX ppid may change)
350        self._ppid = None
351        # platform-specific modules define an _psplatform.Process
352        # implementation class
353        self._proc = _psplatform.Process(pid)
354        self._last_sys_cpu_times = None
355        self._last_proc_cpu_times = None
356        self._exitcode = _SENTINEL
357        # cache creation time for later use in is_running() method
358        try:
359            self.create_time()
360        except AccessDenied:
361            # We should never get here as AFAIK we're able to get
362            # process creation time on all platforms even as a
363            # limited user.
364            pass
365        except ZombieProcess:
366            # Zombies can still be queried by this class (although
367            # not always) and pids() return them so just go on.
368            pass
369        except NoSuchProcess:
370            if not _ignore_nsp:
371                msg = "process PID not found"
372                raise NoSuchProcess(pid, msg=msg)
373            else:
374                self._gone = True
375        # This pair is supposed to identify a Process instance
376        # univocally over time (the PID alone is not enough as
377        # it might refer to a process whose PID has been reused).
378        # This will be used later in __eq__() and is_running().
379        self._ident = (self.pid, self._create_time)
380
381    def __str__(self):
382        info = collections.OrderedDict()
383        info["pid"] = self.pid
384        if self._name:
385            info['name'] = self._name
386        with self.oneshot():
387            try:
388                info["name"] = self.name()
389                info["status"] = self.status()
390            except ZombieProcess:
391                info["status"] = "zombie"
392            except NoSuchProcess:
393                info["status"] = "terminated"
394            except AccessDenied:
395                pass
396            if self._exitcode not in (_SENTINEL, None):
397                info["exitcode"] = self._exitcode
398            if self._create_time is not None:
399                info['started'] = _pprint_secs(self._create_time)
400            return "%s.%s(%s)" % (
401                self.__class__.__module__,
402                self.__class__.__name__,
403                ", ".join(["%s=%r" % (k, v) for k, v in info.items()]),
404            )
405
406    __repr__ = __str__
407
408    def __eq__(self, other):
409        # Test for equality with another Process object based
410        # on PID and creation time.
411        if not isinstance(other, Process):
412            return NotImplemented
413        if OPENBSD or NETBSD:  # pragma: no cover
414            # Zombie processes on Open/NetBSD have a creation time of
415            # 0.0. This covers the case when a process started normally
416            # (so it has a ctime), then it turned into a zombie. It's
417            # important to do this because is_running() depends on
418            # __eq__.
419            pid1, ctime1 = self._ident
420            pid2, ctime2 = other._ident
421            if pid1 == pid2:
422                if ctime1 and not ctime2:
423                    try:
424                        return self.status() == STATUS_ZOMBIE
425                    except Error:
426                        pass
427        return self._ident == other._ident
428
429    def __ne__(self, other):
430        return not self == other
431
432    def __hash__(self):
433        if self._hash is None:
434            self._hash = hash(self._ident)
435        return self._hash
436
437    def _raise_if_pid_reused(self):
438        """Raises NoSuchProcess in case process PID has been reused."""
439        if not self.is_running() and self._pid_reused:
440            # We may directly raise NSP in here already if PID is just
441            # not running, but I prefer NSP to be raised naturally by
442            # the actual Process API call. This way unit tests will tell
443            # us if the API is broken (aka don't raise NSP when it
444            # should). We also remain consistent with all other "get"
445            # APIs which don't use _raise_if_pid_reused().
446            msg = "process no longer exists and its PID has been reused"
447            raise NoSuchProcess(self.pid, self._name, msg=msg)
448
449    @property
450    def pid(self):
451        """The process PID."""
452        return self._pid
453
454    # --- utility methods
455
456    @contextlib.contextmanager
457    def oneshot(self):
458        """Utility context manager which considerably speeds up the
459        retrieval of multiple process information at the same time.
460
461        Internally different process info (e.g. name, ppid, uids,
462        gids, ...) may be fetched by using the same routine, but
463        only one information is returned and the others are discarded.
464        When using this context manager the internal routine is
465        executed once (in the example below on name()) and the
466        other info are cached.
467
468        The cache is cleared when exiting the context manager block.
469        The advice is to use this every time you retrieve more than
470        one information about the process. If you're lucky, you'll
471        get a hell of a speedup.
472
473        >>> import psutil
474        >>> p = psutil.Process()
475        >>> with p.oneshot():
476        ...     p.name()  # collect multiple info
477        ...     p.cpu_times()  # return cached value
478        ...     p.cpu_percent()  # return cached value
479        ...     p.create_time()  # return cached value
480        ...
481        >>>
482        """
483        with self._lock:
484            if hasattr(self, "_cache"):
485                # NOOP: this covers the use case where the user enters the
486                # context twice:
487                #
488                # >>> with p.oneshot():
489                # ...    with p.oneshot():
490                # ...
491                #
492                # Also, since as_dict() internally uses oneshot()
493                # I expect that the code below will be a pretty common
494                # "mistake" that the user will make, so let's guard
495                # against that:
496                #
497                # >>> with p.oneshot():
498                # ...    p.as_dict()
499                # ...
500                yield
501            else:
502                try:
503                    # cached in case cpu_percent() is used
504                    self.cpu_times.cache_activate(self)
505                    # cached in case memory_percent() is used
506                    self.memory_info.cache_activate(self)
507                    # cached in case parent() is used
508                    self.ppid.cache_activate(self)
509                    # cached in case username() is used
510                    if POSIX:
511                        self.uids.cache_activate(self)
512                    # specific implementation cache
513                    self._proc.oneshot_enter()
514                    yield
515                finally:
516                    self.cpu_times.cache_deactivate(self)
517                    self.memory_info.cache_deactivate(self)
518                    self.ppid.cache_deactivate(self)
519                    if POSIX:
520                        self.uids.cache_deactivate(self)
521                    self._proc.oneshot_exit()
522
523    def as_dict(self, attrs=None, ad_value=None):
524        """Utility method returning process information as a
525        hashable dictionary.
526        If *attrs* is specified it must be a list of strings
527        reflecting available Process class' attribute names
528        (e.g. ['cpu_times', 'name']) else all public (read
529        only) attributes are assumed.
530        *ad_value* is the value which gets assigned in case
531        AccessDenied or ZombieProcess exception is raised when
532        retrieving that particular process information.
533        """
534        valid_names = _as_dict_attrnames
535        if attrs is not None:
536            if not isinstance(attrs, (list, tuple, set, frozenset)):
537                msg = "invalid attrs type %s" % type(attrs)
538                raise TypeError(msg)
539            attrs = set(attrs)
540            invalid_names = attrs - valid_names
541            if invalid_names:
542                msg = "invalid attr name%s %s" % (
543                    "s" if len(invalid_names) > 1 else "",
544                    ", ".join(map(repr, invalid_names)),
545                )
546                raise ValueError(msg)
547
548        retdict = {}
549        ls = attrs or valid_names
550        with self.oneshot():
551            for name in ls:
552                try:
553                    if name == 'pid':
554                        ret = self.pid
555                    else:
556                        meth = getattr(self, name)
557                        ret = meth()
558                except (AccessDenied, ZombieProcess):
559                    ret = ad_value
560                except NotImplementedError:
561                    # in case of not implemented functionality (may happen
562                    # on old or exotic systems) we want to crash only if
563                    # the user explicitly asked for that particular attr
564                    if attrs:
565                        raise
566                    continue
567                retdict[name] = ret
568        return retdict
569
570    def parent(self):
571        """Return the parent process as a Process object pre-emptively
572        checking whether PID has been reused.
573        If no parent is known return None.
574        """
575        lowest_pid = _LOWEST_PID if _LOWEST_PID is not None else pids()[0]
576        if self.pid == lowest_pid:
577            return None
578        ppid = self.ppid()
579        if ppid is not None:
580            ctime = self.create_time()
581            try:
582                parent = Process(ppid)
583                if parent.create_time() <= ctime:
584                    return parent
585                # ...else ppid has been reused by another process
586            except NoSuchProcess:
587                pass
588
589    def parents(self):
590        """Return the parents of this process as a list of Process
591        instances. If no parents are known return an empty list.
592        """
593        parents = []
594        proc = self.parent()
595        while proc is not None:
596            parents.append(proc)
597            proc = proc.parent()
598        return parents
599
600    def is_running(self):
601        """Return whether this process is running.
602        It also checks if PID has been reused by another process in
603        which case return False.
604        """
605        if self._gone or self._pid_reused:
606            return False
607        try:
608            # Checking if PID is alive is not enough as the PID might
609            # have been reused by another process: we also want to
610            # verify process identity.
611            # Process identity / uniqueness over time is guaranteed by
612            # (PID + creation time) and that is verified in __eq__.
613            self._pid_reused = self != Process(self.pid)
614            return not self._pid_reused
615        except ZombieProcess:
616            # We should never get here as it's already handled in
617            # Process.__init__; here just for extra safety.
618            return True
619        except NoSuchProcess:
620            self._gone = True
621            return False
622
623    # --- actual API
624
625    @memoize_when_activated
626    def ppid(self):
627        """The process parent PID.
628        On Windows the return value is cached after first call.
629        """
630        # On POSIX we don't want to cache the ppid as it may unexpectedly
631        # change to 1 (init) in case this process turns into a zombie:
632        # https://github.com/giampaolo/psutil/issues/321
633        # http://stackoverflow.com/questions/356722/
634
635        # XXX should we check creation time here rather than in
636        # Process.parent()?
637        self._raise_if_pid_reused()
638        if POSIX:
639            return self._proc.ppid()
640        else:  # pragma: no cover
641            self._ppid = self._ppid or self._proc.ppid()
642            return self._ppid
643
644    def name(self):
645        """The process name. The return value is cached after first call."""
646        # Process name is only cached on Windows as on POSIX it may
647        # change, see:
648        # https://github.com/giampaolo/psutil/issues/692
649        if WINDOWS and self._name is not None:
650            return self._name
651        name = self._proc.name()
652        if POSIX and len(name) >= 15:
653            # On UNIX the name gets truncated to the first 15 characters.
654            # If it matches the first part of the cmdline we return that
655            # one instead because it's usually more explicative.
656            # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
657            try:
658                cmdline = self.cmdline()
659            except (AccessDenied, ZombieProcess):
660                # Just pass and return the truncated name: it's better
661                # than nothing. Note: there are actual cases where a
662                # zombie process can return a name() but not a
663                # cmdline(), see:
664                # https://github.com/giampaolo/psutil/issues/2239
665                pass
666            else:
667                if cmdline:
668                    extended_name = os.path.basename(cmdline[0])
669                    if extended_name.startswith(name):
670                        name = extended_name
671        self._name = name
672        self._proc._name = name
673        return name
674
675    def exe(self):
676        """The process executable as an absolute path.
677        May also be an empty string.
678        The return value is cached after first call.
679        """
680
681        def guess_it(fallback):
682            # try to guess exe from cmdline[0] in absence of a native
683            # exe representation
684            cmdline = self.cmdline()
685            if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
686                exe = cmdline[0]  # the possible exe
687                # Attempt to guess only in case of an absolute path.
688                # It is not safe otherwise as the process might have
689                # changed cwd.
690                if (
691                    os.path.isabs(exe)
692                    and os.path.isfile(exe)
693                    and os.access(exe, os.X_OK)
694                ):
695                    return exe
696            if isinstance(fallback, AccessDenied):
697                raise fallback
698            return fallback
699
700        if self._exe is None:
701            try:
702                exe = self._proc.exe()
703            except AccessDenied as err:
704                return guess_it(fallback=err)
705            else:
706                if not exe:
707                    # underlying implementation can legitimately return an
708                    # empty string; if that's the case we don't want to
709                    # raise AD while guessing from the cmdline
710                    try:
711                        exe = guess_it(fallback=exe)
712                    except AccessDenied:
713                        pass
714                self._exe = exe
715        return self._exe
716
717    def cmdline(self):
718        """The command line this process has been called with."""
719        return self._proc.cmdline()
720
721    def status(self):
722        """The process current status as a STATUS_* constant."""
723        try:
724            return self._proc.status()
725        except ZombieProcess:
726            return STATUS_ZOMBIE
727
728    def username(self):
729        """The name of the user that owns the process.
730        On UNIX this is calculated by using *real* process uid.
731        """
732        if POSIX:
733            if pwd is None:
734                # might happen if python was installed from sources
735                msg = "requires pwd module shipped with standard python"
736                raise ImportError(msg)
737            real_uid = self.uids().real
738            try:
739                return pwd.getpwuid(real_uid).pw_name
740            except KeyError:
741                # the uid can't be resolved by the system
742                return str(real_uid)
743        else:
744            return self._proc.username()
745
746    def create_time(self):
747        """The process creation time as a floating point number
748        expressed in seconds since the epoch.
749        The return value is cached after first call.
750        """
751        if self._create_time is None:
752            self._create_time = self._proc.create_time()
753        return self._create_time
754
755    def cwd(self):
756        """Process current working directory as an absolute path."""
757        return self._proc.cwd()
758
759    def nice(self, value=None):
760        """Get or set process niceness (priority)."""
761        if value is None:
762            return self._proc.nice_get()
763        else:
764            self._raise_if_pid_reused()
765            self._proc.nice_set(value)
766
767    if POSIX:
768
769        @memoize_when_activated
770        def uids(self):
771            """Return process UIDs as a (real, effective, saved)
772            namedtuple.
773            """
774            return self._proc.uids()
775
776        def gids(self):
777            """Return process GIDs as a (real, effective, saved)
778            namedtuple.
779            """
780            return self._proc.gids()
781
782        def terminal(self):
783            """The terminal associated with this process, if any,
784            else None.
785            """
786            return self._proc.terminal()
787
788        def num_fds(self):
789            """Return the number of file descriptors opened by this
790            process (POSIX only).
791            """
792            return self._proc.num_fds()
793
794    # Linux, BSD, AIX and Windows only
795    if hasattr(_psplatform.Process, "io_counters"):
796
797        def io_counters(self):
798            """Return process I/O statistics as a
799            (read_count, write_count, read_bytes, write_bytes)
800            namedtuple.
801            Those are the number of read/write calls performed and the
802            amount of bytes read and written by the process.
803            """
804            return self._proc.io_counters()
805
806    # Linux and Windows
807    if hasattr(_psplatform.Process, "ionice_get"):
808
809        def ionice(self, ioclass=None, value=None):
810            """Get or set process I/O niceness (priority).
811
812            On Linux *ioclass* is one of the IOPRIO_CLASS_* constants.
813            *value* is a number which goes from 0 to 7. The higher the
814            value, the lower the I/O priority of the process.
815
816            On Windows only *ioclass* is used and it can be set to 2
817            (normal), 1 (low) or 0 (very low).
818
819            Available on Linux and Windows > Vista only.
820            """
821            if ioclass is None:
822                if value is not None:
823                    msg = "'ioclass' argument must be specified"
824                    raise ValueError(msg)
825                return self._proc.ionice_get()
826            else:
827                self._raise_if_pid_reused()
828                return self._proc.ionice_set(ioclass, value)
829
830    # Linux / FreeBSD only
831    if hasattr(_psplatform.Process, "rlimit"):
832
833        def rlimit(self, resource, limits=None):
834            """Get or set process resource limits as a (soft, hard)
835            tuple.
836
837            *resource* is one of the RLIMIT_* constants.
838            *limits* is supposed to be a (soft, hard) tuple.
839
840            See "man prlimit" for further info.
841            Available on Linux and FreeBSD only.
842            """
843            if limits is not None:
844                self._raise_if_pid_reused()
845            return self._proc.rlimit(resource, limits)
846
847    # Windows, Linux and FreeBSD only
848    if hasattr(_psplatform.Process, "cpu_affinity_get"):
849
850        def cpu_affinity(self, cpus=None):
851            """Get or set process CPU affinity.
852            If specified, *cpus* must be a list of CPUs for which you
853            want to set the affinity (e.g. [0, 1]).
854            If an empty list is passed, all egible CPUs are assumed
855            (and set).
856            (Windows, Linux and BSD only).
857            """
858            if cpus is None:
859                return sorted(set(self._proc.cpu_affinity_get()))
860            else:
861                self._raise_if_pid_reused()
862                if not cpus:
863                    if hasattr(self._proc, "_get_eligible_cpus"):
864                        cpus = self._proc._get_eligible_cpus()
865                    else:
866                        cpus = tuple(range(len(cpu_times(percpu=True))))
867                self._proc.cpu_affinity_set(list(set(cpus)))
868
869    # Linux, FreeBSD, SunOS
870    if hasattr(_psplatform.Process, "cpu_num"):
871
872        def cpu_num(self):
873            """Return what CPU this process is currently running on.
874            The returned number should be <= psutil.cpu_count()
875            and <= len(psutil.cpu_percent(percpu=True)).
876            It may be used in conjunction with
877            psutil.cpu_percent(percpu=True) to observe the system
878            workload distributed across CPUs.
879            """
880            return self._proc.cpu_num()
881
882    # All platforms has it, but maybe not in the future.
883    if hasattr(_psplatform.Process, "environ"):
884
885        def environ(self):
886            """The environment variables of the process as a dict.  Note: this
887            might not reflect changes made after the process started.
888            """
889            return self._proc.environ()
890
891    if WINDOWS:
892
893        def num_handles(self):
894            """Return the number of handles opened by this process
895            (Windows only).
896            """
897            return self._proc.num_handles()
898
899    def num_ctx_switches(self):
900        """Return the number of voluntary and involuntary context
901        switches performed by this process.
902        """
903        return self._proc.num_ctx_switches()
904
905    def num_threads(self):
906        """Return the number of threads used by this process."""
907        return self._proc.num_threads()
908
909    if hasattr(_psplatform.Process, "threads"):
910
911        def threads(self):
912            """Return threads opened by process as a list of
913            (id, user_time, system_time) namedtuples representing
914            thread id and thread CPU times (user/system).
915            On OpenBSD this method requires root access.
916            """
917            return self._proc.threads()
918
919    def children(self, recursive=False):
920        """Return the children of this process as a list of Process
921        instances, pre-emptively checking whether PID has been reused.
922        If *recursive* is True return all the parent descendants.
923
924        Example (A == this process):
925
926         A ─┐
927            │
928            ├─ B (child) ─┐
929            │             └─ X (grandchild) ─┐
930            │                                └─ Y (great grandchild)
931            ├─ C (child)
932            └─ D (child)
933
934        >>> import psutil
935        >>> p = psutil.Process()
936        >>> p.children()
937        B, C, D
938        >>> p.children(recursive=True)
939        B, X, Y, C, D
940
941        Note that in the example above if process X disappears
942        process Y won't be listed as the reference to process A
943        is lost.
944        """
945        self._raise_if_pid_reused()
946        ppid_map = _ppid_map()
947        ret = []
948        if not recursive:
949            for pid, ppid in ppid_map.items():
950                if ppid == self.pid:
951                    try:
952                        child = Process(pid)
953                        # if child happens to be older than its parent
954                        # (self) it means child's PID has been reused
955                        if self.create_time() <= child.create_time():
956                            ret.append(child)
957                    except (NoSuchProcess, ZombieProcess):
958                        pass
959        else:
960            # Construct a {pid: [child pids]} dict
961            reverse_ppid_map = collections.defaultdict(list)
962            for pid, ppid in ppid_map.items():
963                reverse_ppid_map[ppid].append(pid)
964            # Recursively traverse that dict, starting from self.pid,
965            # such that we only call Process() on actual children
966            seen = set()
967            stack = [self.pid]
968            while stack:
969                pid = stack.pop()
970                if pid in seen:
971                    # Since pids can be reused while the ppid_map is
972                    # constructed, there may be rare instances where
973                    # there's a cycle in the recorded process "tree".
974                    continue
975                seen.add(pid)
976                for child_pid in reverse_ppid_map[pid]:
977                    try:
978                        child = Process(child_pid)
979                        # if child happens to be older than its parent
980                        # (self) it means child's PID has been reused
981                        intime = self.create_time() <= child.create_time()
982                        if intime:
983                            ret.append(child)
984                            stack.append(child_pid)
985                    except (NoSuchProcess, ZombieProcess):
986                        pass
987        return ret
988
989    def cpu_percent(self, interval=None):
990        """Return a float representing the current process CPU
991        utilization as a percentage.
992
993        When *interval* is 0.0 or None (default) compares process times
994        to system CPU times elapsed since last call, returning
995        immediately (non-blocking). That means that the first time
996        this is called it will return a meaningful 0.0 value.
997
998        When *interval* is > 0.0 compares process times to system CPU
999        times elapsed before and after the interval (blocking).
1000
1001        In this case is recommended for accuracy that this function
1002        be called with at least 0.1 seconds between calls.
1003
1004        A value > 100.0 can be returned in case of processes running
1005        multiple threads on different CPU cores.
1006
1007        The returned value is explicitly NOT split evenly between
1008        all available logical CPUs. This means that a busy loop process
1009        running on a system with 2 logical CPUs will be reported as
1010        having 100% CPU utilization instead of 50%.
1011
1012        Examples:
1013
1014          >>> import psutil
1015          >>> p = psutil.Process(os.getpid())
1016          >>> # blocking
1017          >>> p.cpu_percent(interval=1)
1018          2.0
1019          >>> # non-blocking (percentage since last call)
1020          >>> p.cpu_percent(interval=None)
1021          2.9
1022          >>>
1023        """
1024        blocking = interval is not None and interval > 0.0
1025        if interval is not None and interval < 0:
1026            msg = "interval is not positive (got %r)" % interval
1027            raise ValueError(msg)
1028        num_cpus = cpu_count() or 1
1029
1030        def timer():
1031            return _timer() * num_cpus
1032
1033        if blocking:
1034            st1 = timer()
1035            pt1 = self._proc.cpu_times()
1036            time.sleep(interval)
1037            st2 = timer()
1038            pt2 = self._proc.cpu_times()
1039        else:
1040            st1 = self._last_sys_cpu_times
1041            pt1 = self._last_proc_cpu_times
1042            st2 = timer()
1043            pt2 = self._proc.cpu_times()
1044            if st1 is None or pt1 is None:
1045                self._last_sys_cpu_times = st2
1046                self._last_proc_cpu_times = pt2
1047                return 0.0
1048
1049        delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
1050        delta_time = st2 - st1
1051        # reset values for next call in case of interval == None
1052        self._last_sys_cpu_times = st2
1053        self._last_proc_cpu_times = pt2
1054
1055        try:
1056            # This is the utilization split evenly between all CPUs.
1057            # E.g. a busy loop process on a 2-CPU-cores system at this
1058            # point is reported as 50% instead of 100%.
1059            overall_cpus_percent = (delta_proc / delta_time) * 100
1060        except ZeroDivisionError:
1061            # interval was too low
1062            return 0.0
1063        else:
1064            # Note 1:
1065            # in order to emulate "top" we multiply the value for the num
1066            # of CPU cores. This way the busy process will be reported as
1067            # having 100% (or more) usage.
1068            #
1069            # Note 2:
1070            # taskmgr.exe on Windows differs in that it will show 50%
1071            # instead.
1072            #
1073            # Note 3:
1074            # a percentage > 100 is legitimate as it can result from a
1075            # process with multiple threads running on different CPU
1076            # cores (top does the same), see:
1077            # http://stackoverflow.com/questions/1032357
1078            # https://github.com/giampaolo/psutil/issues/474
1079            single_cpu_percent = overall_cpus_percent * num_cpus
1080            return round(single_cpu_percent, 1)
1081
1082    @memoize_when_activated
1083    def cpu_times(self):
1084        """Return a (user, system, children_user, children_system)
1085        namedtuple representing the accumulated process time, in
1086        seconds.
1087        This is similar to os.times() but per-process.
1088        On macOS and Windows children_user and children_system are
1089        always set to 0.
1090        """
1091        return self._proc.cpu_times()
1092
1093    @memoize_when_activated
1094    def memory_info(self):
1095        """Return a namedtuple with variable fields depending on the
1096        platform, representing memory information about the process.
1097
1098        The "portable" fields available on all platforms are `rss` and `vms`.
1099
1100        All numbers are expressed in bytes.
1101        """
1102        return self._proc.memory_info()
1103
1104    @_common.deprecated_method(replacement="memory_info")
1105    def memory_info_ex(self):
1106        return self.memory_info()
1107
1108    def memory_full_info(self):
1109        """This method returns the same information as memory_info(),
1110        plus, on some platform (Linux, macOS, Windows), also provides
1111        additional metrics (USS, PSS and swap).
1112        The additional metrics provide a better representation of actual
1113        process memory usage.
1114
1115        Namely USS is the memory which is unique to a process and which
1116        would be freed if the process was terminated right now.
1117
1118        It does so by passing through the whole process address.
1119        As such it usually requires higher user privileges than
1120        memory_info() and is considerably slower.
1121        """
1122        return self._proc.memory_full_info()
1123
1124    def memory_percent(self, memtype="rss"):
1125        """Compare process memory to total physical system memory and
1126        calculate process memory utilization as a percentage.
1127        *memtype* argument is a string that dictates what type of
1128        process memory you want to compare against (defaults to "rss").
1129        The list of available strings can be obtained like this:
1130
1131        >>> psutil.Process().memory_info()._fields
1132        ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss')
1133        """
1134        valid_types = list(_psplatform.pfullmem._fields)
1135        if memtype not in valid_types:
1136            msg = "invalid memtype %r; valid types are %r" % (
1137                memtype,
1138                tuple(valid_types),
1139            )
1140            raise ValueError(msg)
1141        fun = (
1142            self.memory_info
1143            if memtype in _psplatform.pmem._fields
1144            else self.memory_full_info
1145        )
1146        metrics = fun()
1147        value = getattr(metrics, memtype)
1148
1149        # use cached value if available
1150        total_phymem = _TOTAL_PHYMEM or virtual_memory().total
1151        if not total_phymem > 0:
1152            # we should never get here
1153            msg = (
1154                "can't calculate process memory percent because total physical"
1155                " system memory is not positive (%r)" % (total_phymem)
1156            )
1157            raise ValueError(msg)
1158        return (value / float(total_phymem)) * 100
1159
1160    if hasattr(_psplatform.Process, "memory_maps"):
1161
1162        def memory_maps(self, grouped=True):
1163            """Return process' mapped memory regions as a list of namedtuples
1164            whose fields are variable depending on the platform.
1165
1166            If *grouped* is True the mapped regions with the same 'path'
1167            are grouped together and the different memory fields are summed.
1168
1169            If *grouped* is False every mapped region is shown as a single
1170            entity and the namedtuple will also include the mapped region's
1171            address space ('addr') and permission set ('perms').
1172            """
1173            it = self._proc.memory_maps()
1174            if grouped:
1175                d = {}
1176                for tupl in it:
1177                    path = tupl[2]
1178                    nums = tupl[3:]
1179                    try:
1180                        d[path] = map(lambda x, y: x + y, d[path], nums)
1181                    except KeyError:
1182                        d[path] = nums
1183                nt = _psplatform.pmmap_grouped
1184                return [nt(path, *d[path]) for path in d]  # NOQA
1185            else:
1186                nt = _psplatform.pmmap_ext
1187                return [nt(*x) for x in it]
1188
1189    def open_files(self):
1190        """Return files opened by process as a list of
1191        (path, fd) namedtuples including the absolute file name
1192        and file descriptor number.
1193        """
1194        return self._proc.open_files()
1195
1196    def connections(self, kind='inet'):
1197        """Return socket connections opened by process as a list of
1198        (fd, family, type, laddr, raddr, status) namedtuples.
1199        The *kind* parameter filters for connections that match the
1200        following criteria:

Showing the first 1,200 of 2493 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai