gh-95004: specialize access to enums and fix scaling on free-threading (#148184)

Co-authored-by: Ken Jin <kenjin4096@gmail.com>
This commit is contained in:
Kumar Aditya 2026-04-07 21:43:50 +05:30 committed by GitHub
parent 7e0a0be409
commit e371ce10cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 54 additions and 8 deletions

View file

@ -2047,5 +2047,25 @@ def load_module_attr_missing():
sys.modules.pop("test_module_with_getattr", None)
@cpython_only
@requires_specialization
def test_load_attr_enum(self):
import enum
class Color(enum.IntEnum):
RED = 1
GREEN = 2
BLUE = 3
def load_enum_member():
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
x = Color.RED
assert x == 1
load_enum_member()
self.assert_specialized(load_enum_member,
"LOAD_ATTR_CLASS_WITH_METACLASS_CHECK")
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1 @@
The specializing interpreter now specializes for :class:`enum.Enum` improving performance and scaling in free-threading. Patch by Kumar Aditya.

View file

@ -1201,22 +1201,33 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
}
}
switch (kind) {
case METHOD:
case NON_DESCRIPTOR:
#ifdef Py_GIL_DISABLED
if (!_PyObject_HasDeferredRefcount(descr)) {
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
case MUTABLE:
// special case for enums which has Py_TYPE(descr) == cls
// so guarding on type version is sufficient
if (Py_TYPE(descr) != cls) {
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
Py_XDECREF(descr);
return -1;
}
#endif
write_u32(cache->type_version, tp_version);
if (Py_TYPE(descr)->tp_descr_get || Py_TYPE(descr)->tp_descr_set) {
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
Py_XDECREF(descr);
return -1;
}
_Py_FALLTHROUGH;
case METHOD:
case NON_DESCRIPTOR:
#ifdef Py_GIL_DISABLED
maybe_enable_deferred_ref_count(descr);
#endif
write_ptr(cache->descr, descr);
if (metaclass_check) {
write_u32(cache->keys_version, meta_version);
write_u32(cache->keys_version, tp_version);
write_u32(cache->type_version, meta_version);
specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
}
else {
write_u32(cache->type_version, tp_version);
specialize(instr, LOAD_ATTR_CLASS);
}
Py_XDECREF(descr);

View file

@ -295,6 +295,20 @@ def setattr_non_interned():
setattr(obj, f"{prefix}_c", None)
from enum import Enum
class MyEnum(Enum):
X = 1
Y = 2
Z = 3
@register_benchmark
def enum_attr():
for _ in range(1000 * WORK_SCALE):
MyEnum.X
MyEnum.Y
MyEnum.Z
def bench_one_thread(func):
t0 = time.perf_counter_ns()
func()