-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Support assigning to __class__ #1981
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
Support assigning to __class__ #1981
Conversation
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.
Looks great so far!
vm/src/pyobject.rs
Outdated
| // TODO: make this RwLock once PyObjectRef is Send + Sync | ||
| pub(crate) dict: Option<Mutex<PyDictRef>>, // __dict__ member | ||
| pub(crate) typ: ArcSwap<PyObject<PyClass>>, // __class__ member | ||
| pub(crate) dict: Option<ArcSwap<PyObject<PyDict>>>, // __dict__ member |
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.
Very useful type! I was thinking about using a sort of AtomicArcCell for these fields, but I wasn't sure it would be able to be fully atomic; looks like it is!
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.
It suits out use case pretty well as it's optimised for reading, which is the operation that we really care about here.
|
re: accessing |
|
Or I suppose the field is already |
4972b49 to
a6e49df
Compare
|
I have been able to reduce the performance regression of this PR down to just under 10% by using |
|
What's the performance regression like if you use |
|
That actually made it worse 😢. The benchmark results for master: 1,473,571,865 ns/iter (+/- 9,875,746) I'm a little bit surprised by the amount these change are having on the overall performance. |
|
I guess 3+ atomic ops on every method lookup compared to just an offset of the pyobject does have a decent impact. Kinda just curious now, but how does this compare to a |
|
RwLock test bench_rustpy_mandelbrot 1,318,745,820 ns/iter (+/- 5,858,271) 🎉 The above includes the changes I have made within this PR that reduces the amount of clones that we perform, that is why it's faster than no locking. I'm surprised that the RwLock performs so well. |
|
Under the hood, it looks like arc-swap has their own sort of parking lot with shards and stuff, but that naive implementation with a bunch of work done on each lock + only a limited number of total locks can't beat parking_lot with its 1 atomic op for uncontended locking and "parking lot" for determining contention. |
a6e49df to
16bd28a
Compare
|
This is ready for review now. |
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.
Great work!!
vm/src/pyobject.rs
Outdated
| // TODO: make this RwLock once PyObjectRef is Send + Sync | ||
| pub(crate) dict: Option<Mutex<PyDictRef>>, // __dict__ member | ||
| pub(crate) typ: RwLock<Arc<PyObject<PyClass>>>, // __class__ member | ||
| pub(crate) dict: Option<ArcSwap<PyObject<PyDict>>>, // __dict__ member |
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.
Should we use RwLock for dict as well?
| } | ||
|
|
||
| /// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__, | ||
| /// so only use this if `cls` is known to have not overridden the base __subclasscheck__ magic | ||
| /// method. | ||
| pub fn issubclass(subclass: &PyClassRef, cls: &PyClassRef) -> bool { | ||
| subclass.iter_mro().any(|c| c.is(cls)) | ||
| pub fn issubclass<T: DerefToPyClass + IdProtocol, R: IdProtocol>(subclass: T, cls: R) -> bool { |
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.
Is there any reason you couldn't just do subclass: &PyClass? I think auto-reborrowing would let you pass &PyLease or &PyClassRef for that.
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.
The subclass parameter needs to know it's identity for the case: issubclass(A, A), which &PyClass doesn't know as that's just the payload.
…ant performance difference.
Supports the following:
Note at the moment this incorrectly allows, but this is a wider issue(#1979 ):
I used https://docs.rs/arc-swap/0.4.7/arc_swap/, for both the
typanddictfields withinPyObjectas it seems like that would have a slightly lower overhead than aMutex. A benchmark with just thedictmutex replaced withArcSwapshowed a small improvement. Even with that, this PR has caused a regression of around 25% 😞, due to thetypfield being accesed quite a lot(I think).