-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
Use per-thread reference count for heap type objects in the free-threaded build #122417
Comments
The free-threaded build partially stores heap type reference counts in distributed manner in per-thread arrays. This avoids reference count contention when creating or destroying instances. Co-authored-by: Ken Jin <kenjin@python.org>
The free-threaded build partially stores heap type reference counts in distributed manner in per-thread arrays. This avoids reference count contention when creating or destroying instances. Co-authored-by: Ken Jin <kenjin@python.org>
The free-threaded build partially stores heap type reference counts in distributed manner in per-thread arrays. This avoids reference count contention when creating or destroying instances. Co-authored-by: Ken Jin <kenjin@python.org>
Since this delays freeing heap types until the next collection, would it make sense to defer the references from instances to their class? It we make all references from objects headers to their class deferred then there will be no need to update the reference count at all. It would be simpler than this mechanism. |
I don't think we can treat the
We only scan GC tracked objects (and stacks). We don't visit untracked objects or non-GC objects, but those objects should still keep their types alive. |
The free-threaded build partially stores heap type reference counts in distributed manner in per-thread arrays. This avoids reference count contention when creating or destroying instances. Co-authored-by: Ken Jin <kenjin@python.org>
Feature or enhancement
Overview
As described in PEP 703, heap type objects use a mix of reference counting techniques in the free-threaded build. They use deferred reference counting (see #117376) in combination with with per-thread reference counting. Deferred reference counting alone is not sufficient to address the multi-threaded scaling bottlenecks with heap types because most references to heap types are from object instances, not references on the interpreter stack.
To address this, heap type reference counts are partially stored in a distributed manner in per-thread arrays. Every thread stores an array of local reference counts for each heap type object. A heap type's true reference count is the sum of:
ob_ref_local
andob_ref_shared
)_PyThreadStateImpl
Mechanics
Two new internal functions for reference counting types:
void _Py_INCREF_TYPE(PyTypeObject *type)
void _Py_DECREF_TYPE(PyTypeObject *type)
These are like
Py_INCREF
andPy_DECREF
, but modify the per-thread reference counts when possible. If necessary, they fallback toPy_INCREF/DECREF
. In the default build, these just callPy_INCREF/DECREF
. Note that it's always safe to callPy_INCREF
instead of_Py_INCREF_TYPE
; it's just that_Py_INCREF_TYPE
avoids scalability bottlenecks in some cases.The free-threaded GC will scan the per-thread refcount arrays when computing an object's reference count in addition to scanning each thread's stack for deferred reference counting.
We'll also need some code to manage the lifetime and resizing of the per-thread refcount arrays.
Internal Usages
_PyObject_Init
should call_Py_INCREF_TYPE(typeobj)
instead ofPy_INCREF(typeobj)
. (The PEP saysPyType_GenericAlloc
, but_PyObject_Init
is now the right place to do it.)subtype_dealloc
should call_Py_DECREF_TYPE(type)
instead ofPy_DECREF(type)
. (Same as described in the PEP).Additionally, with the conversion of some static types to heap types, we now use the following
tp_dealloc
pattern in more places:We will eventually want to change internal usages to the following to avoid reference count contention on
tp
:Linked PRs
The text was updated successfully, but these errors were encountered: