diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-04 21:12:37 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-04 21:12:37 +0100 |
commit | ab4a66a6e942ba505bb5b0be6fefadeceaef6809 (patch) | |
tree | e0f14084e890a29d00a065a8cb1bcf530b71fa11 | |
parent | f670047cf99c9578b63c05c066c93befed6ff1cf (diff) | |
download | psutil-ab4a66a6e942ba505bb5b0be6fefadeceaef6809.tar.gz |
provide a new memory_addrspace_info() fun and deprecate memory_info_ex
-rw-r--r-- | psutil/__init__.py | 45 | ||||
-rw-r--r-- | psutil/_common.py | 19 | ||||
-rw-r--r-- | psutil/_pslinux.py | 40 | ||||
-rw-r--r-- | psutil/_psosx.py | 14 | ||||
-rw-r--r-- | psutil/_pswindows.py | 24 | ||||
-rw-r--r-- | test/_linux.py | 8 | ||||
-rw-r--r-- | test/test_psutil.py | 53 |
7 files changed, 99 insertions, 104 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py index be68951f..e53e918d 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -26,6 +26,7 @@ except ImportError: pwd = None from . import _common +from ._common import deprecated_method from ._common import memoize from ._compat import callable from ._compat import long @@ -965,15 +966,14 @@ class Process(object): """ return self._proc.memory_info() + @deprecated_method(replacement="memory_info") def memory_info_ex(self): - """Return a namedtuple with variable fields depending on the - platform representing extended memory information about - this process. All numbers are expressed in bytes. - """ - return self._proc.memory_info_ex() + return self.memory_info() + + if hasattr(_psplatform.Process, "memory_addrspace_info"): - def memory_info_addrspace(self): - pass + def memory_addrspace_info(self): + return self._proc.memory_addrspace_info() def memory_percent(self, memtype="rss"): """Compare process memory to total physical system memory and @@ -982,20 +982,27 @@ class Process(object): process memory you want to compare against (defaults to "rss"). The list of available strings can be obtained like this: - >>> psutil.Process().memory_info_ex()._fields + >>> psutil.Process().memory_info()._fields ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss') """ - if memtype in ("rss", "vsz"): - value = getattr(self.memory_info(), memtype) + if memtype in ('uss', 'pss'): + if not hasattr(self, "memory_addrspace_info"): + fields = _psplatform.pmem._fields + raise ValueError( + "invalid memtype %r; valid types are %r" % ( + memtype, fields)) + fun = self.memory_addrspace_info + fields = _psplatform.paddrspmem._fields + else: - memex = self.memory_info_ex() - if memtype not in memex._fields: - raise ValueError("invalid memtype %r; valid types are %r" % ( - memtype, memex._fields)) - value = getattr(memex, memtype) - if value == 0 and memtype in ('uss', 'pss'): - raise AccessDenied(self.pid, self._name, - msg="can't retrieve %s memory" % memtype) + fields = _psplatform.pmem._fields + fun = self.memory_info + + if memtype not in fields: + raise ValueError("invalid memtype %r; valid types are %r" % ( + memtype, fields)) + metrics = fun() + value = getattr(metrics, memtype) # use cached value if available total_phymem = _TOTAL_PHYMEM or virtual_memory().total @@ -1987,7 +1994,7 @@ def test(): # pragma: no cover pinfo['name'].strip() or '?')) -del memoize, division +del memoize, division, deprecated_method if sys.version_info < (3, 0): del num diff --git a/psutil/_common.py b/psutil/_common.py index 78d59309..92b3b5e1 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -13,6 +13,7 @@ import os import socket import stat import sys +import warnings from collections import namedtuple from socket import AF_INET from socket import SOCK_DGRAM @@ -229,6 +230,24 @@ def socktype_to_enum(num): return num +def deprecated_method(replacement): + """A decorator which can be used to mark a method as deprecated + 'replcement' is the method name which will be called instead. + """ + def outer(fun): + msg = "%s() is deprecated; use %s() instead" % ( + fun.__name__, replacement) + if fun.__doc__ is None: + fun.__doc__ = msg + + @functools.wraps(fun) + def inner(self, *args, **kwargs): + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) + return getattr(self, replacement)(*args, **kwargs) + return inner + return outer + + # --- Process.connections() 'kind' parameter mapping conn_tmap = { diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 22a95e58..8f54dfeb 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -219,7 +219,7 @@ svmem = namedtuple( 'active', 'inactive', 'buffers', 'cached']) pmem = namedtuple('pmem', 'rss vms shared text lib data dirty') -pextmem = namedtuple('pextmem', 'rss vms shared text lib data dirty uss pss') +paddrspmem = namedtuple('paddrspmem', ['uss', 'pss']) pmmap_grouped = namedtuple( 'pmmap_grouped', ['path', 'rss', 'size', 'pss', 'shared_clean', @@ -970,35 +970,23 @@ class Process(object): [int(x) * PAGESIZE for x in f.readline().split()[:7]] return pmem(rss, vms, shared, text, lib, data, dirty) - @wrap_exceptions - def memory_info_ex(self, - _private_re=re.compile(b"Private.*:\s+(\d+)"), - _pss_re=re.compile(b"Pss.*:\s+(\d+)")): - base_mem = self.memory_info() - uss = pss = 0 - if HAS_SMAPS: + if HAS_SMAPS: + + @wrap_exceptions + def memory_addrspace_info( + self, + _private_re=re.compile(b"Private.*:\s+(\d+)"), + _pss_re=re.compile(b"Pss.*:\s+(\d+)")): # Note: using two regexes is faster than reading the file # line by line. # XXX: on Python 3 the 2 regexes are 30% slower than on # Python 2 though. Figure out why. - try: - with open_binary("%s/%s/smaps" % (self._procfs_path, self.pid), - buffering=BIGGER_FILE_BUFFERING) as f: - smaps_data = f.read() - except EnvironmentError as err: - if err.errno not in (errno.EPERM, errno.EACCES): - raise - else: - uss = sum(map(int, _private_re.findall(smaps_data))) * 1024 - pss = sum(map(int, _pss_re.findall(smaps_data))) * 1024 - else: - # usually means we're on kernel < 2.6.14 or CONFIG_MMU kernel - # configuration option is not enabled. - pass - - return pextmem(*base_mem + (uss, pss)) - - if HAS_SMAPS: + with open_binary("%s/%s/smaps" % (self._procfs_path, self.pid), + buffering=BIGGER_FILE_BUFFERING) as f: + smaps_data = f.read() + uss = sum(map(int, _private_re.findall(smaps_data))) * 1024 + pss = sum(map(int, _pss_re.findall(smaps_data))) * 1024 + return paddrspmem(uss, pss) @wrap_exceptions def memory_maps(self): diff --git a/psutil/_psosx.py b/psutil/_psosx.py index e78f8784..e3439dde 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -59,7 +59,7 @@ svmem = namedtuple( 'active', 'inactive', 'wired']) pmem = namedtuple('pextmem', ['rss', 'vms', 'pfaults', 'pageins']) -pextmem = namedtuple('pextmem', ['rss', 'vms', 'pfaults', 'pageins', 'uss']) +paddrspmem = namedtuple('paddrspmem', ['uss', 'pss']) pmmap_grouped = namedtuple( 'pmmap_grouped', @@ -274,15 +274,9 @@ class Process(object): return pmem(rss, vms, pfaults, pageins) @wrap_exceptions - def memory_info_ex(self): - base_mem = self.memory_info() - uss = 0 - try: - uss = cext.proc_memory_uss(self.pid) - except OSError as err: - if err.errno not in (errno.EPERM, errno.EACCES): - raise - return pextmem(*base_mem + (uss, )) + def memory_addrspace_info(self): + uss = cext.proc_memory_uss(self.pid) + return paddrspmem(uss) @wrap_exceptions def cpu_times(self): diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 9635a3d4..a9167551 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -84,10 +84,11 @@ if enum is not None: scputimes = namedtuple('scputimes', ['user', 'system', 'idle']) svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) -pextmem = namedtuple( - 'pextmem', ['num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', - 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', - 'pagefile', 'peak_pagefile', 'private', 'uss']) +pmem = namedtuple( + 'pmem', ['num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', + 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', + 'pagefile', 'peak_pagefile', 'private']) +paddrspmem = namedtuple('paddrspmem', ['uss']) pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss']) pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) @@ -359,14 +360,6 @@ class Process(object): return cext.proc_memory_info_2(self.pid) raise - def _get_uss_mem(self): - try: - return cext.proc_memory_uss(self.pid) - except OSError as err: - if err.errno in ACCESS_DENIED_SET: - return 0 - raise - @wrap_exceptions def memory_info(self): # on Windows RSS == WorkingSetSize and VSM == PagefileUsage @@ -377,10 +370,9 @@ class Process(object): return _common.pmem(t[2], t[7]) @wrap_exceptions - def memory_info_ex(self): - info = self._get_raw_meminfo() - uss = self._get_uss_mem() - return pextmem(*info + (uss, )) + def memory_addrspace_info(self): + uss = cext.proc_memory_uss(self.pid) + return paddrspmem(uss) def memory_maps(self): try: diff --git a/test/_linux.py b/test/_linux.py index 637ad1f7..cebd21a4 100644 --- a/test/_linux.py +++ b/test/_linux.py @@ -599,7 +599,7 @@ class LinuxSpecificTestCase(unittest.TestCase): self.assertEqual(psutil.Process().exe(), "/home/foo") self.assertEqual(psutil.Process().cwd(), "/home/foo") - def test_uss_pss_mem_against_mem_maps(self): + def test_memory_addrspace_info(self): src = textwrap.dedent(""" import time with open("%s", "w") as f: @@ -610,12 +610,12 @@ class LinuxSpecificTestCase(unittest.TestCase): call_until(lambda: os.listdir('.'), "'%s' not in ret" % TESTFN) p = psutil.Process(sproc.pid) time.sleep(.1) - memex = p.memory_info_ex() + mem = p.memory_addrspace_info() maps = p.memory_maps(grouped=False) self.assertEqual( - memex.uss, sum([x.private_dirty + x.private_clean for x in maps])) + mem.uss, sum([x.private_dirty + x.private_clean for x in maps])) self.assertEqual( - memex.pss, sum([x.shared_dirty + x.shared_clean for x in maps])) + mem.pss, sum([x.pss for x in maps])) def main(): diff --git a/test/test_psutil.py b/test/test_psutil.py index 9bd6eddf..e8017cf3 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1685,22 +1685,21 @@ class TestProcess(unittest.TestCase): rss2, vms2 = p.memory_info()[:2] percent2 = p.memory_percent() - # make sure that the memory usage bumped up + + # step 3 - make sure that the memory usage bumped up self.assertGreater(rss2, rss1) self.assertGreaterEqual(vms2, vms1) # vms might be equal self.assertGreater(percent2, percent1) del memarr - def test_memory_info_ex(self): - memex = psutil.Process().memory_info_ex() - if LINUX or OSX or WINDOWS: - self.assertGreater(memex.uss, 0) - if LINUX: - self.assertGreater(memex.pss, 0) - self.assertGreater(memex.pss, memex.uss) - base_mem = psutil.Process().memory_info() - self.assertEqual(memex.rss, base_mem.rss) - self.assertEqual(memex.vms, base_mem.vms) + @unittest.skipUnless(LINUX or OSX or WINDOWS, + "not available on this platform") + def test_memory_addrspace_info(self): + mem = psutil.Process().memory_addrspace_info() + self.assertGreater(mem.uss, 0) + if LINUX: + self.assertGreater(mem.pss, 0) + self.assertGreater(mem.pss, mem.uss) @unittest.skipIf(OPENBSD or NETBSD, "not available on this platform") def test_memory_maps(self): @@ -1739,20 +1738,12 @@ class TestProcess(unittest.TestCase): assert 0 <= ret <= 100, ret ret = p.memory_percent(memtype='vms') assert 0 <= ret <= 100, ret - memtype = psutil._psplatform.pextmem._fields[-1] - ret = p.memory_percent(memtype=memtype) assert 0 <= ret <= 100, ret self.assertRaises(ValueError, p.memory_percent, memtype="?!?") - - @unittest.skipUnless(LINUX or OSX or WINDOWS, - "uss not available on this plaftorm") - def test_memory_percent_uss_ad(self): - ret = collections.namedtuple("pextm", "rss vms uss")(1, 1, 0) - with mock.patch("psutil._psplatform.Process.memory_info_ex", - return_value=ret): - p = psutil.Process() - self.assertRaises( - psutil.AccessDenied, p.memory_percent, memtype="uss") + if LINUX or OSX or WINDOWS: + ret = p.memory_percent(memtype='uss') + assert 0 <= ret <= 100, ret + assert 0 <= ret <= 100, ret def test_is_running(self): sproc = get_test_subprocess(wait=True) @@ -2603,7 +2594,9 @@ class TestFetchAllProcesses(unittest.TestCase): valid_procs = 0 excluded_names = set([ 'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', - 'as_dict', 'cpu_percent', 'parent', 'children', 'pid']) + 'as_dict', 'cpu_percent', 'parent', 'children', 'pid', + 'memory_info_ex', + ]) if LINUX and not RLIMIT_SUPPORT: excluded_names.add('rlimit') attrs = [] @@ -2753,12 +2746,8 @@ class TestFetchAllProcesses(unittest.TestCase): self.assertTrue(ret.system >= 0) def memory_info(self, ret, proc): - self.assertTrue(ret.rss >= 0) - self.assertTrue(ret.vms >= 0) - - def memory_info_ex(self, ret, proc): for name in ret._fields: - self.assertTrue(getattr(ret, name) >= 0) + self.assertGreaterEqual(getattr(ret, name), 0) if POSIX and ret.vms != 0: # VMS is always supposed to be the highest for name in ret._fields: @@ -2771,6 +2760,12 @@ class TestFetchAllProcesses(unittest.TestCase): assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret assert ret.peak_pagefile >= ret.pagefile, ret + def memory_addrspace_info(self, ret, proc): + for name in ret._fields: + self.assertGreaterEqual(getattr(ret, name), 0) + if LINUX: + self.assertGreaterEqual(ret.pss, ret.uss) + def open_files(self, ret, proc): for f in ret: if WINDOWS: |