summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2018-12-13 15:54:37 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2018-12-13 15:54:37 +0100
commit2cdf81db322822ba8fb23ed67523aacb6539da95 (patch)
treeee946d6f3200eafd2dafdee78e68c899426ebf8e
parent8351fa4ff642d997cd478a7d216b661e62a5f696 (diff)
downloadpsutil-2cdf81db322822ba8fb23ed67523aacb6539da95.tar.gz
#1373: different approach to oneshot() cache (pass Process instances around - which is faster)
-rw-r--r--psutil/__init__.py16
-rw-r--r--psutil/_common.py25
-rw-r--r--psutil/_psaix.py14
-rw-r--r--psutil/_psbsd.py6
-rw-r--r--psutil/_pslinux.py14
-rw-r--r--psutil/_psosx.py10
-rw-r--r--psutil/_pssunos.py14
-rw-r--r--psutil/_pswindows.py6
-rwxr-xr-xpsutil/tests/test_misc.py4
-rwxr-xr-xpsutil/tests/test_process.py15
10 files changed, 70 insertions, 54 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 5a5720d7..78ff985d 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -471,23 +471,23 @@ class Process(object):
self._oneshot_inctx = True
try:
# cached in case cpu_percent() is used
- self.cpu_times.cache_activate()
+ self.cpu_times.cache_activate(self)
# cached in case memory_percent() is used
- self.memory_info.cache_activate()
+ self.memory_info.cache_activate(self)
# cached in case parent() is used
- self.ppid.cache_activate()
+ self.ppid.cache_activate(self)
# cached in case username() is used
if POSIX:
- self.uids.cache_activate()
+ self.uids.cache_activate(self)
# specific implementation cache
self._proc.oneshot_enter()
yield
finally:
- self.cpu_times.cache_deactivate()
- self.memory_info.cache_deactivate()
- self.ppid.cache_deactivate()
+ self.cpu_times.cache_deactivate(self)
+ self.memory_info.cache_deactivate(self)
+ self.ppid.cache_deactivate(self)
if POSIX:
- self.uids.cache_deactivate()
+ self.uids.cache_deactivate(self)
self._proc.oneshot_exit()
self._oneshot_inctx = False
diff --git a/psutil/_common.py b/psutil/_common.py
index bee95792..f498bb90 100644
--- a/psutil/_common.py
+++ b/psutil/_common.py
@@ -327,7 +327,7 @@ def memoize_when_activated(fun):
1
>>>
>>> # activated
- >>> foo.cache_activate()
+ >>> foo.cache_activate(self)
>>> foo()
1
>>> foo()
@@ -336,26 +336,27 @@ def memoize_when_activated(fun):
"""
@functools.wraps(fun)
def wrapper(self):
- if not wrapper.cache_activated:
+ if not hasattr(self, "_cache"):
return fun(self)
else:
try:
- ret = cache[fun]
+ ret = self._cache[fun]
except KeyError:
- ret = cache[fun] = fun(self)
+ ret = self._cache[fun] = fun(self)
return ret
- def cache_activate():
- """Activate cache."""
- wrapper.cache_activated = True
+ def cache_activate(proc):
+ """Activate cache. Expects a Process instance. Cache will be
+ stored as a "_cache" instance attribute."""
+ proc._cache = {}
- def cache_deactivate():
+ def cache_deactivate(proc):
"""Deactivate and clear cache."""
- wrapper.cache_activated = False
- cache.clear()
+ try:
+ del proc._cache
+ except AttributeError:
+ pass
- cache = {}
- wrapper.cache_activated = False
wrapper.cache_activate = cache_activate
wrapper.cache_deactivate = cache_deactivate
return wrapper
diff --git a/psutil/_psaix.py b/psutil/_psaix.py
index 7ba212db..9975545a 100644
--- a/psutil/_psaix.py
+++ b/psutil/_psaix.py
@@ -354,7 +354,7 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
+ __slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -363,14 +363,14 @@ class Process(object):
self._procfs_path = get_procfs_path()
def oneshot_enter(self):
- self._proc_name_and_args.cache_activate()
- self._proc_basic_info.cache_activate()
- self._proc_cred.cache_activate()
+ self._proc_name_and_args.cache_activate(self)
+ self._proc_basic_info.cache_activate(self)
+ self._proc_cred.cache_activate(self)
def oneshot_exit(self):
- self._proc_name_and_args.cache_deactivate()
- self._proc_basic_info.cache_deactivate()
- self._proc_cred.cache_deactivate()
+ self._proc_name_and_args.cache_deactivate(self)
+ self._proc_basic_info.cache_deactivate(self)
+ self._proc_cred.cache_deactivate(self)
@memoize_when_activated
def _proc_name_and_args(self):
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 1dc72312..6683a200 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -594,7 +594,7 @@ def wrap_exceptions_procfs(inst):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name", "_ppid"]
+ __slots__ = ["pid", "_name", "_ppid", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -609,10 +609,10 @@ class Process(object):
return ret
def oneshot_enter(self):
- self.oneshot.cache_activate()
+ self.oneshot.cache_activate(self)
def oneshot_exit(self):
- self.oneshot.cache_deactivate()
+ self.oneshot.cache_deactivate(self)
@wrap_exceptions
def name(self):
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 880be2c8..5c8cc20c 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -1528,7 +1528,7 @@ def wrap_exceptions(fun):
class Process(object):
"""Linux process implementation."""
- __slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
+ __slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -1585,14 +1585,14 @@ class Process(object):
return f.read().strip()
def oneshot_enter(self):
- self._parse_stat_file.cache_activate()
- self._read_status_file.cache_activate()
- self._read_smaps_file.cache_activate()
+ self._parse_stat_file.cache_activate(self)
+ self._read_status_file.cache_activate(self)
+ self._read_smaps_file.cache_activate(self)
def oneshot_exit(self):
- self._parse_stat_file.cache_deactivate()
- self._read_status_file.cache_deactivate()
- self._read_smaps_file.cache_deactivate()
+ self._parse_stat_file.cache_deactivate(self)
+ self._read_status_file.cache_deactivate(self)
+ self._read_smaps_file.cache_deactivate(self)
@wrap_exceptions
def name(self):
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index 94e22bc7..015c5b41 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -380,7 +380,7 @@ def catch_zombie(proc):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name", "_ppid"]
+ __slots__ = ["pid", "_name", "_ppid", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -403,12 +403,12 @@ class Process(object):
return ret
def oneshot_enter(self):
- self._get_kinfo_proc.cache_activate()
- self._get_pidtaskinfo.cache_activate()
+ self._get_kinfo_proc.cache_activate(self)
+ self._get_pidtaskinfo.cache_activate(self)
def oneshot_exit(self):
- self._get_kinfo_proc.cache_deactivate()
- self._get_pidtaskinfo.cache_deactivate()
+ self._get_kinfo_proc.cache_deactivate(self)
+ self._get_pidtaskinfo.cache_deactivate(self)
@wrap_exceptions
def name(self):
diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py
index e2f33a3a..730af393 100644
--- a/psutil/_pssunos.py
+++ b/psutil/_pssunos.py
@@ -368,7 +368,7 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
+ __slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -377,14 +377,14 @@ class Process(object):
self._procfs_path = get_procfs_path()
def oneshot_enter(self):
- self._proc_name_and_args.cache_activate()
- self._proc_basic_info.cache_activate()
- self._proc_cred.cache_activate()
+ self._proc_name_and_args.cache_activate(self)
+ self._proc_basic_info.cache_activate(self)
+ self._proc_cred.cache_activate(self)
def oneshot_exit(self):
- self._proc_name_and_args.cache_deactivate()
- self._proc_basic_info.cache_deactivate()
- self._proc_cred.cache_deactivate()
+ self._proc_name_and_args.cache_deactivate(self)
+ self._proc_basic_info.cache_deactivate(self)
+ self._proc_cred.cache_deactivate(self)
@memoize_when_activated
def _proc_name_and_args(self):
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 2bc9c9dd..bb588242 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -645,7 +645,7 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name", "_ppid"]
+ __slots__ = ["pid", "_name", "_ppid", "_cache"]
def __init__(self, pid):
self.pid = pid
@@ -655,10 +655,10 @@ class Process(object):
# --- oneshot() stuff
def oneshot_enter(self):
- self.oneshot_info.cache_activate()
+ self.oneshot_info.cache_activate(self)
def oneshot_exit(self):
- self.oneshot_info.cache_deactivate()
+ self.oneshot_info.cache_deactivate(self)
@memoize_when_activated
def oneshot_info(self):
diff --git a/psutil/tests/test_misc.py b/psutil/tests/test_misc.py
index 3056abc0..93132b55 100755
--- a/psutil/tests/test_misc.py
+++ b/psutil/tests/test_misc.py
@@ -261,14 +261,14 @@ class TestMisc(unittest.TestCase):
# activate
calls = []
- f.foo.cache_activate()
+ f.foo.cache_activate(f)
f.foo()
f.foo()
self.assertEqual(len(calls), 1)
# deactivate
calls = []
- f.foo.cache_deactivate()
+ f.foo.cache_deactivate(f)
f.foo()
f.foo()
self.assertEqual(len(calls), 2)
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index 2126e32a..cd72be85 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -1195,6 +1195,21 @@ class TestProcess(unittest.TestCase):
p.cpu_times()
self.assertEqual(m.call_count, 2)
+ def test_oneshot_cache(self):
+ # Make sure oneshot() cache is nonglobal. Instead it's
+ # supposed to be bound to the Process instance, see:
+ # https://github.com/giampaolo/psutil/issues/1373
+ p1, p2 = create_proc_children_pair()
+ p1_ppid = p1.ppid()
+ p2_ppid = p2.ppid()
+ self.assertNotEqual(p1_ppid, p2_ppid)
+ with p1.oneshot():
+ self.assertEqual(p1.ppid(), p1_ppid)
+ self.assertEqual(p2.ppid(), p2_ppid)
+ with p2.oneshot():
+ self.assertEqual(p1.ppid(), p1_ppid)
+ self.assertEqual(p2.ppid(), p2_ppid)
+
def test_halfway_terminated_process(self):
# Test that NoSuchProcess exception gets raised in case the
# process dies after we create the Process object.