-
Notifications
You must be signed in to change notification settings - Fork 594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make BoundedAttributes constructor more efficient #3331
Make BoundedAttributes constructor more efficient #3331
Conversation
There is no risk of locking issues during a constructor call. It is also not desirable to lock-unlock-... for each provided attribute to the constructor. This commit seeks to improve on these by refactoring __setitem__ such that the 'body' inside the lock context manager is moved to a separate method _unsafe__setitem. This method can then be called by internal methods without taking the lock first. Another method 'update' (overridden from MutableMapping) is added that takes the lock *once* and then calls another new method _unsafe_update, which in turn simply iterates the attribute items and calls _unsafe__setitem on them.
These changes seem fine to me. I'm still ramping up on this repo so hopefully others will correct me if I'm overstepping, but what do you think about adding test coverage for correctness? |
Thanks for the PR!
I would expect this to be a hot function if you're sampling a lot because it is called every span creation (code), but it's not clear how much the PR actual improves performance. I am also on board with something like this, but it would be nice to see at least some Did you see specifically that the locking was taking the most time in the profile? |
@@ -162,25 +162,41 @@ def __repr__(self): | |||
def __getitem__(self, key): | |||
return self._dict[key] | |||
|
|||
def _unsafe__setitem(self, key, value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use unlocked
instead of unsafe
? It is more accurate IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe thread_unsafe
?
Right, we need at least unit tests for these changes. |
Hi @torarvid, thank you for your help. Do you have availability to continue with this PR? |
Hi, @pmcollins 👋 Sorry for the huge delay here. I'm currently on paternity leave (and have been for a few months), so very little time for coding at the moment. I have seen the request for some timeit results, and I believe it's possible I have jumped the gun with this PR... 🤦♂️ I realize now that I of course should have tested the performance of this before claiming the locking was the issue — but I didn't do that before creating the patch. So it's entirely possible that I'm not really improving things here. If there is anyone who wants to take this over, anyone should feel free to do that. Otherwise, I'm still interested in improving things and will be back at work start of January. |
Thanks torarvid. We're happy to take it from here. Based on some simple testing, this change appears to yield a small (~2%) performance improvement in constructor execution time. Will discuss with the SIG how proceed with this and other pending PRs as well. Thanks!
Before:
After:
|
238b8e8
to
6128e00
Compare
# Conflicts: # opentelemetry-api/src/opentelemetry/attributes/__init__.py
My thought after looking at this PR again is that the 2% performance improvement in the constructor may not be worth the added complexity at this point (it really depends on how often this constructor runs :). If we do want to pursue this, I think a simpler implementation would be to temporarily use a no-op lock during constructor execution. |
Shall we close this ticket? |
I think we can close this PR and reopen when it has test cases. |
Discussed in the SIG, agreed to close this PR. |
Description
There is no risk of locking issues during a constructor call. It is also not desirable to lock-unlock-... for each provided attribute to the constructor.
This commit seeks to improve on these by refactoring
__setitem__
such that the 'body' inside the lock context manager is moved to a separate method_unsafe__setitem
. This method can then be called by internal methods without taking the lock first.Another method
update
(overridden fromMutableMapping
) is added that takes the lock once and then calls another new method_unsafe_update
, which in turn simply iterates the attribute items and calls_unsafe__setitem
on them.(I haven't created a corresponding issue, please tell me if this is required)
Motivation
We use opentelemetry-python at work, and this constructor is showing up quite a bit in our cpu profiles when using py-spy.
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
I have simply run
tox
locally 😬 🙈Does This PR Require a Contrib Repo Change?
Answer the following question based on these examples of changes that would require a Contrib Repo Change:
Checklist: