Repository navigation
gh-115999: Specialize LOAD_ATTR for instance and class receivers in free-threaded builds
#128164
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
Changes from 1 commit
8eeb4fe
fcd05a0
5c03db0
a576748
8475fd6
29c3356
4f9eeb3
e9050fc
ade57f2
0a87264
816e22f
ca1e232
945b61c
feb7d34
ecfd199
9fda5db
3b2c220
408e44b
16aab70
d0920ea
e7cea82
8dac8c4
d29b3aa
b0b8102
85dab0d
581869e
96be738
9afe052
e190a0d
8c78369
cdf8eb5
1398699
3fbe18b
5aa68cc
e1bf1f4
396edb1
e5e2508
fa02260
47c794f
3876bc7
08d14d0
56e9a8a
8ca405b
4c7a4b9
1b787b3
b868363
d6d4c73
9755562
9673f78
6c3041f
a20a4a4
35b31c6
e5a7ae9
bb00f5a
b6ae487
11a351d
6f8aebf
07b7c20
1870885
f1fdcc6
8b71951
7190a2e
8b96368
db02869
dc3ba7f
e07fb62
a3f89b7
3baa840
9250e4e
675eb82
d24dc3a
10d693d
7ab3ec6
8c70ea4
3616eab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Use atomic load for value - Use _Py_TryIncrefCompareStackRef for incref
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2142,12 +2142,18 @@ dummy_func( | |
| split op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { | ||
| PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); | ||
| PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); | ||
| PyObject *attr_o = *value_ptr; | ||
| PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); | ||
| DEOPT_IF(attr_o == NULL); | ||
| STAT_INC(LOAD_ATTR, hit); | ||
| #ifdef Py_GIL_DISABLED | ||
| if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does I know that
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is an atomic compare-and-incref function, similar to how "Compare" is a more appropriate term than "consistent" here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think "Compare" is misleading. The name should say what the function does, not how it does it. |
||
| DEOPT_IF(true); | ||
| } | ||
| #else | ||
| Py_INCREF(attr_o); | ||
| null = PyStackRef_NULL; | ||
| attr = PyStackRef_FromPyObjectSteal(attr_o); | ||
| #endif | ||
| STAT_INC(LOAD_ATTR, hit); | ||
| null = PyStackRef_NULL; | ||
| DECREF_INPUTS(); | ||
| } | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
How do we know that the values array is still valid at this point?
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.
There's a case that we are not handling correctly here: if, after loading
value_ptr, another thread invalidates the inline values, modifies an attribute, and reallocates another object at the same memory address as the previous attribute, we can incorrectly return a value that wasn't the attribute at that offset.We need to either:
_PyObject_InlineValues(owner_o)->validat the end of this handler and clean-up and deopt if it's not still true._Py_TryIncrefCompareStackRefhandles this case and correctly deopts.I think the second options is probably simpler to implement and more efficient given that
_LOAD_ATTR_INSTANCE_VALUEis common and invalidating inline values is relatively rare.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.
Invalidating inline values might not be that rare.
I suggest gathering some stats before deciding how to handle this.
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.
From
https://github.com/faster-cpython/benchmarking-public/blob/main/results/bm-20250104-3.14.0a3%2B-0cafa97/bm-20250104-azure-x86_64-python-0cafa97932c6574734bb-3.14.0a3%2B-0cafa97-pystats.md:
LOAD_ATTR_INSTANCE_VALUE: 4,922,474,147
Materialize dict (on request) | 4,444,396 | 2.4%
Materialize dict (new key) | 476,375 | 0.3%
Materialize dict (too big) | 4,884 | 0.0%
Materialize dict (str subclass) | 0 | 0.0%
So, LOAD_ATTR_INSTANCE_VALUE is somewhere between 1,000x-10,000x more frequent than invalidating inline values. (Invalidating inline values requires first materializing the dictionary, but materializing the dictionary doesn't always invalidate the inline values).