From 7537f6008704b20e2d04a7ef1c0cfa34121cc5eb Mon Sep 17 00:00:00 2001 From: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> Date: Tue, 4 Jan 2022 13:05:09 -0500 Subject: bpo-45609: More specialization stats for STORE_SUBSCR (GH-30193) --- Python/specialize.c | 71 ++++++++++++++++++++++++++++++++++++++-- Tools/scripts/summarize_stats.py | 4 +-- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 8991fa9..2da9e0f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -486,6 +486,13 @@ initial_counter_value(void) { #define SPEC_FAIL_BUFFER_SLICE 16 #define SPEC_FAIL_SEQUENCE_INT 17 +/* Store subscr */ +#define SPEC_FAIL_BYTEARRAY_INT 18 +#define SPEC_FAIL_BYTEARRAY_SLICE 19 +#define SPEC_FAIL_PY_SIMPLE 20 +#define SPEC_FAIL_PY_OTHER 21 +#define SPEC_FAIL_DICT_SUBCLASS_NO_OVERRIDE 22 + /* Binary add */ #define SPEC_FAIL_NON_FUNCTION_SCOPE 11 @@ -1253,15 +1260,73 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins goto fail; } } - else if (container_type == &PyDict_Type) { + if (container_type == &PyDict_Type) { *instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT, initial_counter_value()); goto success; } - else { - SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); +#ifdef Py_STATS + PyMappingMethods *as_mapping = container_type->tp_as_mapping; + if (as_mapping && (as_mapping->mp_ass_subscript + == PyDict_Type.tp_as_mapping->mp_ass_subscript)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_DICT_SUBCLASS_NO_OVERRIDE); goto fail; } + if (PyObject_CheckBuffer(container)) { + if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); + } + else if (strcmp(container_type->tp_name, "array.array") == 0) { + if (PyLong_CheckExact(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_ARRAY_INT); + } + else if (PySlice_Check(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_ARRAY_SLICE); + } + else { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); + } + } + else if (PyByteArray_CheckExact(container)) { + if (PyLong_CheckExact(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_BYTEARRAY_INT); + } + else if (PySlice_Check(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_BYTEARRAY_SLICE); + } + else { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); + } + } + else { + if (PyLong_CheckExact(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_BUFFER_INT); + } + else if (PySlice_Check(sub)) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_BUFFER_SLICE); + } + else { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); + } + } + goto fail; + } + _Py_IDENTIFIER(__setitem__); + PyObject *descriptor = _PyType_LookupId(container_type, &PyId___setitem__); + if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { + PyFunctionObject *func = (PyFunctionObject *)descriptor; + PyCodeObject *code = (PyCodeObject *)func->func_code; + int kind = function_kind(code); + if (kind == SIMPLE_FUNCTION) { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_PY_SIMPLE); + } + else { + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_PY_OTHER); + } + goto fail; + } +#endif + SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); fail: STAT_INC(STORE_SUBSCR, failure); assert(!PyErr_Occurred()); diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index a5a8e93..3a77125 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -28,7 +28,7 @@ TOTAL = "specialization.deferred", "specialization.hit", "specialization.miss", def print_specialization_stats(name, family_stats): if "specialization.deferred" not in family_stats: return - total = sum(family_stats[kind] for kind in TOTAL) + total = sum(family_stats.get(kind, 0) for kind in TOTAL) if total == 0: return print(name+":") @@ -44,7 +44,7 @@ def print_specialization_stats(name, family_stats): for key in ("specialization.success", "specialization.failure"): label = key[len("specialization."):] print(f" {label}:{family_stats.get(key, 0):>12}") - total_failures = family_stats["specialization.failure"] + total_failures = family_stats.get("specialization.failure", 0) failure_kinds = [ 0 ] * 30 for key in family_stats: if not key.startswith("specialization.failure_kind"): -- cgit v0.12