mirror of
https://github.com/python/cpython.git
synced 2025-07-16 15:55:18 +00:00
gh-117783: Immortalize objects that use deferred reference counting (#118112)
Deferred reference counting is not fully implemented yet. As a temporary measure, we immortalize objects that would use deferred reference counting to avoid multi-threaded scaling bottlenecks. This is only performed in the free-threaded build once the first non-main thread is started. Additionally, some tests, including refleak tests, suppress this behavior.
This commit is contained in:
parent
8d4b756fd3
commit
7ccacb220d
13 changed files with 134 additions and 8 deletions
|
@ -704,6 +704,12 @@ _PyGC_Init(PyInterpreterState *interp)
|
|||
{
|
||||
GCState *gcstate = &interp->gc;
|
||||
|
||||
if (_Py_IsMainInterpreter(interp)) {
|
||||
// gh-117783: immortalize objects that would use deferred refcounting
|
||||
// once the first non-main thread is created.
|
||||
gcstate->immortalize.enable_on_thread_created = 1;
|
||||
}
|
||||
|
||||
gcstate->garbage = PyList_New(0);
|
||||
if (gcstate->garbage == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
|
@ -1781,6 +1787,30 @@ custom_visitor_wrapper(const mi_heap_t *heap, const mi_heap_area_t *area,
|
|||
return true;
|
||||
}
|
||||
|
||||
// gh-117783: Immortalize objects that use deferred reference counting to
|
||||
// temporarily work around scaling bottlenecks.
|
||||
static bool
|
||||
immortalize_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
|
||||
void *block, size_t block_size, void *args)
|
||||
{
|
||||
PyObject *op = op_from_block(block, args, false);
|
||||
if (op != NULL && _PyObject_HasDeferredRefcount(op)) {
|
||||
_Py_SetImmortal(op);
|
||||
op->ob_gc_bits &= ~_PyGC_BITS_DEFERRED;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
_PyGC_ImmortalizeDeferredObjects(PyInterpreterState *interp)
|
||||
{
|
||||
struct visitor_args args;
|
||||
_PyEval_StopTheWorld(interp);
|
||||
gc_visit_heaps(interp, &immortalize_visitor, &args);
|
||||
interp->gc.immortalize.enabled = 1;
|
||||
_PyEval_StartTheWorld(interp);
|
||||
}
|
||||
|
||||
void
|
||||
PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
|
||||
{
|
||||
|
|
|
@ -1568,6 +1568,17 @@ new_threadstate(PyInterpreterState *interp, int whence)
|
|||
// Must be called with lock unlocked to avoid re-entrancy deadlock.
|
||||
PyMem_RawFree(new_tstate);
|
||||
}
|
||||
else {
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (interp->gc.immortalize.enable_on_thread_created &&
|
||||
!interp->gc.immortalize.enabled)
|
||||
{
|
||||
// Immortalize objects marked as using deferred reference counting
|
||||
// the first time a non-main thread is created.
|
||||
_PyGC_ImmortalizeDeferredObjects(interp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
// Must be called with lock unlocked to avoid lock ordering deadlocks.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue