Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enable deferred reference counting for mutable class attributes to improve free-threading scaling
3 changes: 3 additions & 0 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,9 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
// special case for enums which has Py_TYPE(descr) == cls
// so guarding on type version is sufficient
if (Py_TYPE(descr) != cls) {
#ifdef Py_GIL_DISABLED
maybe_enable_deferred_ref_count(descr);
#endif
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
Py_XDECREF(descr);
return -1;
Expand Down
19 changes: 19 additions & 0 deletions Tools/ftscalingbench/ftscalingbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,25 @@ def enum_attr():
MyEnum.Z


class _SharedAttrValue:
pass

class MyClassWithSharedAttr:
# A class attribute whose value is an instance of a *different* class.
# Reading it from multiple threads did not scale because LOAD_ATTR_CLASS
# cannot specialize this case (the value's type is not the owner class),
# leaving the shared value's reference count contended on every read.
attr = _SharedAttrValue()

@register_benchmark
def class_attribute():
obj = MyClassWithSharedAttr
for _ in range(1000 * WORK_SCALE):
obj.attr
obj.attr
obj.attr


def bench_one_thread(func):
t0 = time.perf_counter_ns()
func()
Expand Down
Loading