Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
Speed up cached function access #2075
Conversation
erikjohnston
requested a review
from richvdh
Mar 28, 2017
erikjohnston
changed the title from
Speed up the cache
to
Speed up cached function access
Mar 28, 2017
erikjohnston
assigned
richvdh
Mar 28, 2017
| @@ -101,7 +101,7 @@ def remove(r): | ||
| return d | ||
| else: | ||
| success, res = self._result | ||
| - return defer.succeed(res) if success else defer.fail(res) | ||
| + return res if success else defer.fail(res) |
richvdh
Mar 30, 2017
Member
to be clear: I'm not suggesting doing much about it, other than watching for breakage when it lands.
erikjohnston
Mar 30, 2017
Owner
To be honest I'm concerned about this, but it makes cache hits much cheaper.
| @@ -200,6 +200,7 @@ def __init__(self, orig, num_args, inlineCallbacks, cache_context=False): | ||
| arg_spec = inspect.getargspec(orig) | ||
| all_args = arg_spec.args | ||
| + self.arg_spec = arg_spec |
| @@ -229,6 +230,14 @@ def __init__(self, orig, num_args, inlineCallbacks, cache_context=False): | ||
| self.num_args = num_args | ||
| self.arg_names = all_args[1:num_args + 1] | ||
| + if arg_spec.defaults: | ||
| + self.arg_defaults = dict(zip( |
| @@ -311,6 +311,9 @@ def preserve_context_over_deferred(deferred, context=None): | ||
| """Given a deferred wrap it such that any callbacks added later to it will | ||
| be invoked with the current context. | ||
| """ | ||
| + if not isinstance(deferred, defer.Deferred): |
richvdh
Mar 29, 2017
Member
I am not in favour of further bodges on top of preserve_context_over_deferred, since afaict it is broken. Let me send you a counter-PR here.
|
ok so this now has a conflict, and I think the |
richvdh
assigned
erikjohnston
and unassigned
richvdh
Mar 30, 2017
|
Thanks for doing the preserve PR! Will rebase this in a bit |
erikjohnston
added some commits
Mar 28, 2017
|
@richvdh PTAL |
erikjohnston
assigned
richvdh
and unassigned
erikjohnston
Mar 30, 2017
| @@ -101,7 +101,7 @@ def remove(r): | ||
| return d | ||
| else: | ||
| success, res = self._result | ||
| - return defer.succeed(res) if success else defer.fail(res) | ||
| + return res if success else defer.fail(res) |
| self.arg_names = all_args[1:num_args + 1] | ||
| + # The arg spec of the wrapped function, see `inspect.getargspec` for | ||
| + # the type. | ||
| + self.arg_spec = arg_spec |
| @@ -341,7 +370,10 @@ def onErr(f): | ||
| cache.set(cache_key, result_d, callback=invalidate_callback) | ||
| observer = result_d.observe() | ||
| - return logcontext.make_deferred_yieldable(observer) | ||
| + if isinstance(observer, defer.Deferred): |
richvdh
Mar 30, 2017
Member
make_deferred_yieldable will work ok with a non-deferred, so I think this is redundant. otoh I guess it optimises the common path?
erikjohnston
Mar 30, 2017
Owner
Because some of the speed up comes from not having to bounce through all the deferred stuff (which is much more complicated than just unwrapping to get the value) at the call sites.
Though we can also leave that to another PR
| @@ -315,6 +315,9 @@ def preserve_context_over_deferred(deferred, context=None): | ||
| the deferred follow the synapse logcontext rules: try | ||
| ``make_deferred_yieldable`` instead. | ||
| """ | ||
| + if not isinstance(deferred, defer.Deferred): |
richvdh
assigned
erikjohnston
and unassigned
richvdh
Mar 30, 2017
erikjohnston
added some commits
Mar 30, 2017
|
The concern that changing a bunch of functions to sometimes return deferreds is a bit risky, though at worst it should only cause an exception to be raised when someone tries to add a callback to the value returned. (i.e., we're not going to get incorrect values coming out) |
| self.arg_names = all_args[1:num_args + 1] | ||
| + # The arg spec of the wrapped function, see `inspect.getargspec` for | ||
| + # the type. | ||
| + self.arg_spec = arg_spec |
| @@ -341,7 +370,10 @@ def onErr(f): | ||
| cache.set(cache_key, result_d, callback=invalidate_callback) | ||
| observer = result_d.observe() | ||
| - return logcontext.make_deferred_yieldable(observer) | ||
| + if isinstance(observer, defer.Deferred): |
erikjohnston commentedMar 28, 2017
Calls to cached functions are starting to turn up in the flame graphs of matrix.org.
We improve it by doing two things:
yield func(..)which happily deals with it.These two changes speed up cache access by 10x on my desktop.