diff --git a/Python/ceval.c b/Python/ceval.c index 02e4e7b9e4d54f..958ca11409c322 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4447,6 +4447,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr call_shape.total_args = oparg; call_shape.kwnames = NULL; +#ifdef Py_STATS + extern int _PySpecialization_ClassifyCallable(PyObject *); + _py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure++; + _py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure_kinds[_PySpecialization_ClassifyCallable(call_shape.callable)]++; +#endif DISPATCH(); } diff --git a/Python/specialize.c b/Python/specialize.c index b5e4de5d6d2171..940ab172d55fe2 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -175,6 +175,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats) /* Mark some opcodes as specializable for stats, * even though we don't specialize them yet. */ fprintf(out, " opcode[%d].specializable : 1\n", FOR_ITER); + fprintf(out, " opcode[%d].specializable : 1\n", PRECALL_FUNCTION); fprintf(out, " opcode[%d].specializable : 1\n", UNPACK_SEQUENCE); for (int i = 0; i < 256; i++) { if (adaptive_opcodes[i]) { @@ -556,7 +557,7 @@ initial_counter_value(void) { #define SPEC_FAIL_CALL_BAD_CALL_FLAGS 17 #define SPEC_FAIL_CALL_CLASS 18 #define SPEC_FAIL_CALL_PYTHON_CLASS 19 -#define SPEC_FAIL_CALL_C_METHOD_CALL 20 +#define SPEC_FAIL_CALL_METHOD_DESCRIPTOR 20 #define SPEC_FAIL_CALL_BOUND_METHOD 21 #define SPEC_FAIL_CALL_STR 22 #define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 23 @@ -564,6 +565,7 @@ initial_counter_value(void) { #define SPEC_FAIL_CALL_KWNAMES 25 #define SPEC_FAIL_CALL_METHOD_WRAPPER 26 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27 +#define SPEC_FAIL_CALL_PYFUNCTION 28 /* COMPARE_OP */ #define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 @@ -1651,7 +1653,13 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, static int call_fail_kind(PyObject *callable) { - if (PyInstanceMethod_Check(callable)) { + if (PyCFunction_CheckExact(callable)) { + return SPEC_FAIL_CALL_PYCFUNCTION; + } + else if (PyFunction_Check(callable)) { + return SPEC_FAIL_CALL_PYFUNCTION; + } + else if (PyInstanceMethod_Check(callable)) { return SPEC_FAIL_CALL_INSTANCE_METHOD; } else if (PyMethod_Check(callable)) { @@ -1662,7 +1670,15 @@ call_fail_kind(PyObject *callable) return SPEC_FAIL_CALL_CMETHOD; } else if (PyType_Check(callable)) { - return SPEC_FAIL_CALL_CLASS; + if (((PyTypeObject *)callable)->tp_new == PyBaseObject_Type.tp_new) { + return SPEC_FAIL_CALL_PYTHON_CLASS; + } + else { + return SPEC_FAIL_CALL_CLASS; + } + } + else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { + return SPEC_FAIL_CALL_METHOD_DESCRIPTOR; } else if (Py_TYPE(callable) == &PyWrapperDescr_Type) { return SPEC_FAIL_CALL_OPERATOR_WRAPPER; @@ -1905,6 +1921,8 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, adaptive->counter = initial_counter_value(); } +#ifdef Py_STATS + int _PySpecialization_ClassifyIterator(PyObject *iter) { @@ -1966,3 +1984,11 @@ _PySpecialization_ClassifySequence(PyObject *seq) } return SPEC_FAIL_OTHER; } + +int +_PySpecialization_ClassifyCallable(PyObject *callable) +{ + return call_fail_kind(callable); +} + +#endif diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 6e0286f52a0ea6..f6e5b333b09fcb 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -114,6 +114,8 @@ def kind_to_text(kind, defines, opname): opname = "ATTR" if opname.endswith("SUBSCR"): opname = "SUBSCR" + if opname.startswith("PRECALL"): + opname = "CALL" for name in defines[kind]: if name.startswith(opname): return pretty(name[len(opname)+1:])