Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
20 changes: 20 additions & 0 deletions Lib/test/test_opcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The specializing interpreter now specializes for :class:`enum.Enum` improving performance and better scaling in free-threading. Patch by Kumar Aditya.
22 changes: 16 additions & 6 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,15 +1201,25 @@ 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
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_u32(cache->type_version, tp_version);
write_ptr(cache->descr, descr);
if (metaclass_check) {
Expand Down
14 changes: 14 additions & 0 deletions Tools/ftscalingbench/ftscalingbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading