GeezerVison is showing github.com — gh-132657: Add maybe_enable_deferred_ref_count(). by nascheme · Pull Request #142843 · python/cpython
Conversation
nascheme
commented
Dec 16, 2025
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
If we are specializing to LOAD_GLOBAL_MODULE or LOAD_ATTR_MODULE, try to enable deferred reference counting for the value, if the object is owned by a different thread.
Add a benchmark to ftscalingbench.py that shows the benefit of this change. The deepcopy benchmark uses globals like _local_atomic_types.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
eendebakpt reacted with eyes emoji
If we are specializing to LOAD_GLOBAL_MODULE, set deferred reference
counting for the value, if it meets criteria. For now, it's only done
for frozenset objects.
Use it for LOAD_ATTR_MODULE in addition to LOAD_GLOBAL_MODULE. Don't
enable deferred ref counts if the object is owned by the current thread.
Specialized bytecode is per-thread so this works. Enable for
frozensets, tuples and type objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes sense and is worth doing. Let's also add a scaling test to ftscalingbench.py
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Comment on lines
+362
to
+365
|
|
PyObject *op;
|
|
|
if (PyDict_GetItemRef(dict, name, &op) != 1) {
|
|
|
return;
|
|
|
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's combine this lookup with the earlier _PyDict_LookupIndex. _PyDict_LookupIndex already gets the value internally and throws it away.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Comment on lines
+366
to
+371
|
|
if (_Py_IsOwnedByCurrentThread(op) ||
|
|
|
!PyType_IS_GC(Py_TYPE(op)) ||
|
|
|
_PyObject_HasDeferredRefcount(op)) {
|
|
|
Py_DECREF(op);
|
|
|
return;
|
|
|
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The !PyType_IS_GC and _PyObject_HasDeferredRefcount checks aren't really necessary because PyUnstable_Object_EnableDeferredRefcount handles those cases internally.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Comment on lines
+372
to
+374
|
|
if (PyFrozenSet_Check(op) || PyTuple_Check(op) || PyType_Check(op)) {
|
|
|
PyUnstable_Object_EnableDeferredRefcount(op);
|
|
|
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should do this for all objects, not just a few types. Otherwise, I think we will keep run into scaling bottlenecks with global variables.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
eendebakpt reacted with thumbs up emoji
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm... That's going to push a lot of objects to the GC for deallocation in programs that do a lot of work at the global level (but do have a few functions that are called enough that use those globals.) I'm thinking of naively written "scripts". Then again, it would only do that for objects that participate in GC (i.e. not strings or integers), so it's probably fine. I mean, nobody's too surprised when things aren't deallocated quite as quickly as they expect... right?
Yeah, I think this should be fine for main. I definitely wouldn't backport it to 3.14.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
colesbury
Dec 17, 2025
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely agree regarding not backporting to 3.14.
I think the above check that excludes owned by the current thread should help with most scripts -- it'll only affect global variables accessed by multiple threads.
Another thing that may help is that I think the PyUnstable_Object_EnableDeferredRefcount call only happens at specialization time, not every time a variable is updated or accessed.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm a bit worried about increased memory usage. Since it's only for objects shared between threads and only for hot LOAD_GLOBAL/LOAD_ATTR instructions, maybe it's okay. Perhaps we should consider changing gc_should_collect() to check not only the young object count but also the process memory size increase as well. The condition with count < gcstate->long_lived_total / 4 could be done with an "or" condition with the process size check.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Also, avoid PyDict_GetItemRef() call by returning the value when the
index is looked up (as previously discarded).
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️
Hi! The buildbot ARM64 macOS 3.x (tier-2) has failed when building commit bb25f72.
What do you need to do:
- Don't panic.
- Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
- Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/725/builds/12575) and take a look at the build logs.
- Check if the failure is related to this commit (bb25f72) or if it is a false positive.
- If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.
You can take a look at the buildbot page here:
https://buildbot.python.org/#/builders/725/builds/12575
Failed tests:
Summary of the results of the build (if available):
==
Click to see traceback logs
remote: Enumerating objects: 17, done.
remote: Counting objects: 6% (1/16)
remote: Counting objects: 12% (2/16)
remote: Counting objects: 18% (3/16)
remote: Counting objects: 25% (4/16)
remote: Counting objects: 31% (5/16)
remote: Counting objects: 37% (6/16)
remote: Counting objects: 43% (7/16)
remote: Counting objects: 50% (8/16)
remote: Counting objects: 56% (9/16)
remote: Counting objects: 62% (10/16)
remote: Counting objects: 68% (11/16)
remote: Counting objects: 75% (12/16)
remote: Counting objects: 81% (13/16)
remote: Counting objects: 87% (14/16)
remote: Counting objects: 93% (15/16)
remote: Counting objects: 100% (16/16)
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 33% (1/3)
remote: Compressing objects: 66% (2/3)
remote: Compressing objects: 100% (3/3)
remote: Compressing objects: 100% (3/3), done.
remote: Total 17 (delta 13), reused 13 (delta 13), pack-reused 1 (from 1)
From https://github.com/python/cpython
* branch main -> FETCH_HEAD
Note: switching to 'bb25f7280af30831fffa3345b4fc93798949c6c6'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at bb25f7280af gh-132657: Add maybe_enable_deferred_ref_count() (gh-142843)
Switched to and reset branch 'main'
make: *** [buildbottest] Error 2
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
thunder-coding
pushed a commit
to thunder-coding/cpython
that referenced
this pull request
Feb 15, 2026
If we are specializing to `LOAD_GLOBAL_MODULE` or `LOAD_ATTR_MODULE`, try
to enable deferred reference counting for the value, if the object is owned by
a different thread. This applies to the free-threaded build only and should
improve scaling of multi-threaded programs.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|