-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
Integrate trashcan mechanism into _Py_Dealloc #89060
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
Comments
This is a WIP/proof-of-concept of doing away with Py_TRASHCAN_BEGIN and Py_TRASHCAN_END and instead integrating the functionality into _Py_Dealloc. There are a few advantages:
This proof-of-concept seems to pass tests but it will need some careful review. The exact rules related to calling GC Track/Untrack are subtle and this changes things a bit. I.e. tp_dealloc is called with GC objects already untracked. For 3rd party extensions, they are calling PyObject_GC_UnTrack() and so I believe they should still work. The fact that PyObject_CallFinalizerFromDealloc() wants GC objects to definitely be tracked is a bit of a mystery to me (there is an assert to check that). I changed the code to track objects if they are not already tracked but I'm not sure that's correct. There could be a performance hit, due to the _PyType_IS_GC() test that was added to the _Py_Dealloc() function. For non-GC objects, that's going to be a new branch and I'm worried it might hurt a bit. OTOH, maybe it's just in the noise. Profiling will need to be done. |
As I suspected, the performance impact is significant (although pretty small). Based on Linux perf, it looks like the extra test+branch in _Py_Dealloc adds about 1% overhead. pyperformance shows something similar, see attached reports (pypref-trashcan.txt and perf-annotate-trash.txt). An idea I've been trying is to add another type slot, e.g. tp_call_dealloc. It could be set by PyType_Ready(). It would be called by the Py_DECREF macro on refcnt going to zero. If the object is non-GC and Py_TRACE_REFS is off, can make tp_call_dealloc actually be the tp_dealloc pointer. If the type has the GC flag, point tp_call_dealloc to a _Py_Dealloc version that checks tp_is_gc and does the trashcan stuff. Unfortunately, all types don't have PyType_Ready() called on them. So, we cannot rely on tp_call_dealloc being set correctly. |
Based on some testing, I think an extra type slot is not worth the extra complication. I made some small improvements to _Py_Dealloc and now the performance seems a bit better. Basically, I expanded _PyObject_IS_GC() to put the most common branches first. See pypref-trashcan2.txt for benchmark. Overall I think might be a bit slower (less than 1%?) but we have gained trashcan protection for the dealloc of all GC objects. If we are okay with the performance, here are other questions to answer: A) is it safe to untrack GC objects before calling tp_dealloc? B) is it safe to have PyObject_CallFinalizerFromDealloc() track objects that are resurrected? We might have to look at 3rd party extensions to decide on those. I.e. maybe in theory it is not safe but in practice there is no extension code that would actually break. |
Replaced by new PR GH-124716 |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: