From e07e29114af50138d2ab360bb72dd6b045b27913 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 15 Aug 2026 19:28:35 -0400 Subject: [PATCH 1/2] Defer reference count mutable class attributes Mutable class attributes would not scale with more threads, adding defered reference counting to resolve it. ./python_main.exe Tools/ftscalingbench/ftscalingbench.py class_attribute Running benchmarks with 18 threads class_attribute 6.3x slower ./python.exe Tools/ftscalingbench/ftscalingbench.py class_attribute Running benchmarks with 18 threads class_attribute 8.0x faster --- Python/specialize.c | 3 +++ Tools/ftscalingbench/ftscalingbench.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Python/specialize.c b/Python/specialize.c index 773b55c329c7720..2695fcb85edc00a 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -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; diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py index c8a914c22a9e137..609d71ed19df5cd 100644 --- a/Tools/ftscalingbench/ftscalingbench.py +++ b/Tools/ftscalingbench/ftscalingbench.py @@ -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() From f8f4ae3c3d830bee6b78bd977a345da16c92949c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 23:32:54 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-08-15-23-32-52.gh-issue-139103.d8pm7q.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-08-15-23-32-52.gh-issue-139103.d8pm7q.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-15-23-32-52.gh-issue-139103.d8pm7q.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-15-23-32-52.gh-issue-139103.d8pm7q.rst new file mode 100644 index 000000000000000..0fd62c333c42e3d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-15-23-32-52.gh-issue-139103.d8pm7q.rst @@ -0,0 +1 @@ +Enable deferred reference counting for mutable class attributes to improve free-threading scaling