diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2018-12-13 15:54:37 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2018-12-13 15:54:37 +0100 |
commit | 2cdf81db322822ba8fb23ed67523aacb6539da95 (patch) | |
tree | ee946d6f3200eafd2dafdee78e68c899426ebf8e | |
parent | 8351fa4ff642d997cd478a7d216b661e62a5f696 (diff) | |
download | psutil-2cdf81db322822ba8fb23ed67523aacb6539da95.tar.gz |
#1373: different approach to oneshot() cache (pass Process instances around - which is faster)
-rw-r--r-- | psutil/__init__.py | 16 | ||||
-rw-r--r-- | psutil/_common.py | 25 | ||||
-rw-r--r-- | psutil/_psaix.py | 14 | ||||
-rw-r--r-- | psutil/_psbsd.py | 6 | ||||
-rw-r--r-- | psutil/_pslinux.py | 14 | ||||
-rw-r--r-- | psutil/_psosx.py | 10 | ||||
-rw-r--r-- | psutil/_pssunos.py | 14 | ||||
-rw-r--r-- | psutil/_pswindows.py | 6 | ||||
-rwxr-xr-x | psutil/tests/test_misc.py | 4 | ||||
-rwxr-xr-x | psutil/tests/test_process.py | 15 |
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. |