bpo-46072: Add detailed failure stats for BINARY_OP (GH-31289)

This commit is contained in:
Brandt Bucher 2022-02-16 08:49:58 -08:00 committed by GitHub
parent a9da085015
commit 580cd9ab29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 11 deletions

View file

@ -0,0 +1 @@
Add more detailed specialization failure statistics for :opcode:`BINARY_OP`.

View file

@ -552,9 +552,28 @@ initial_counter_value(void) {
#define SPEC_FAIL_SUBSCR_PY_OTHER 21
#define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22
/* Binary add */
/* Binary op */
#define SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES 12
#define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES 8
#define SPEC_FAIL_BINARY_OP_ADD_OTHER 9
#define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES 10
#define SPEC_FAIL_BINARY_OP_AND_INT 11
#define SPEC_FAIL_BINARY_OP_AND_OTHER 12
#define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE 13
#define SPEC_FAIL_BINARY_OP_LSHIFT 14
#define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY 15
#define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES 16
#define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER 17
#define SPEC_FAIL_BINARY_OP_OR 18
#define SPEC_FAIL_BINARY_OP_POWER 19
#define SPEC_FAIL_BINARY_OP_REMAINDER 20
#define SPEC_FAIL_BINARY_OP_RSHIFT 21
#define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES 22
#define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER 23
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 24
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 25
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 26
#define SPEC_FAIL_BINARY_OP_XOR 27
/* Calls */
#define SPEC_FAIL_CALL_COMPLEX_PARAMETERS 9
@ -1745,6 +1764,76 @@ _Py_Specialize_CallNoKw(
return 0;
}
#ifdef Py_STATS
static int
binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
{
switch (oparg) {
case NB_ADD:
case NB_INPLACE_ADD:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES;
}
return SPEC_FAIL_BINARY_OP_ADD_OTHER;
case NB_AND:
case NB_INPLACE_AND:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES;
}
if (PyLong_CheckExact(lhs)) {
return SPEC_FAIL_BINARY_OP_AND_INT;
}
return SPEC_FAIL_BINARY_OP_AND_OTHER;
case NB_FLOOR_DIVIDE:
case NB_INPLACE_FLOOR_DIVIDE:
return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
case NB_LSHIFT:
case NB_INPLACE_LSHIFT:
return SPEC_FAIL_BINARY_OP_LSHIFT;
case NB_MATRIX_MULTIPLY:
case NB_INPLACE_MATRIX_MULTIPLY:
return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY;
case NB_MULTIPLY:
case NB_INPLACE_MULTIPLY:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES;
}
return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
case NB_OR:
case NB_INPLACE_OR:
return SPEC_FAIL_BINARY_OP_OR;
case NB_POWER:
case NB_INPLACE_POWER:
return SPEC_FAIL_BINARY_OP_POWER;
case NB_REMAINDER:
case NB_INPLACE_REMAINDER:
return SPEC_FAIL_BINARY_OP_REMAINDER;
case NB_RSHIFT:
case NB_INPLACE_RSHIFT:
return SPEC_FAIL_BINARY_OP_RSHIFT;
case NB_SUBTRACT:
case NB_INPLACE_SUBTRACT:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES;
}
return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER;
case NB_TRUE_DIVIDE:
case NB_INPLACE_TRUE_DIVIDE:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES;
}
if (PyFloat_CheckExact(lhs)) {
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT;
}
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
case NB_XOR:
case NB_INPLACE_XOR:
return SPEC_FAIL_BINARY_OP_XOR;
}
Py_UNREACHABLE();
}
#endif
void
_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache)
@ -1754,8 +1843,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
case NB_ADD:
case NB_INPLACE_ADD:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
goto failure;
break;
}
if (PyUnicode_CheckExact(lhs)) {
if (_Py_OPCODE(instr[1]) == STORE_FAST && Py_REFCNT(lhs) == 2) {
@ -1780,8 +1868,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
case NB_MULTIPLY:
case NB_INPLACE_MULTIPLY:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
goto failure;
break;
}
if (PyLong_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_INT,
@ -1797,8 +1884,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
case NB_SUBTRACT:
case NB_INPLACE_SUBTRACT:
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
goto failure;
break;
}
if (PyLong_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT,
@ -1811,14 +1897,19 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
goto success;
}
break;
#ifndef Py_STATS
default:
// These operators don't have any available specializations. Rather
// than repeatedly attempting to specialize them, just convert them
// back to BINARY_OP (while still recording a failure, of course)!
// back to BINARY_OP (unless we're collecting stats, where it's more
// important to get accurate hit counts for the unadaptive version
// and each of the different failure types):
*instr = _Py_MAKECODEUNIT(BINARY_OP, adaptive->original_oparg);
return;
#endif
}
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_OTHER);
failure:
SPECIALIZATION_FAIL(
BINARY_OP, binary_op_fail_kind(adaptive->original_oparg, lhs, rhs));
STAT_INC(BINARY_OP, failure);
cache_backoff(adaptive);
return;