Skip to content

Commit 580cd9a

Browse files
authored
bpo-46072: Add detailed failure stats for BINARY_OP (GH-31289)
1 parent a9da085 commit 580cd9a

File tree

2 files changed

+104
-12
lines changed

2 files changed

+104
-12
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add more detailed specialization failure statistics for :opcode:`BINARY_OP`.

Python/specialize.c

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -552,9 +552,28 @@ initial_counter_value(void) {
552552
#define SPEC_FAIL_SUBSCR_PY_OTHER 21
553553
#define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22
554554

555-
/* Binary add */
556-
557-
#define SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES 12
555+
/* Binary op */
556+
557+
#define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES 8
558+
#define SPEC_FAIL_BINARY_OP_ADD_OTHER 9
559+
#define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES 10
560+
#define SPEC_FAIL_BINARY_OP_AND_INT 11
561+
#define SPEC_FAIL_BINARY_OP_AND_OTHER 12
562+
#define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE 13
563+
#define SPEC_FAIL_BINARY_OP_LSHIFT 14
564+
#define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY 15
565+
#define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES 16
566+
#define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER 17
567+
#define SPEC_FAIL_BINARY_OP_OR 18
568+
#define SPEC_FAIL_BINARY_OP_POWER 19
569+
#define SPEC_FAIL_BINARY_OP_REMAINDER 20
570+
#define SPEC_FAIL_BINARY_OP_RSHIFT 21
571+
#define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES 22
572+
#define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER 23
573+
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 24
574+
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 25
575+
#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 26
576+
#define SPEC_FAIL_BINARY_OP_XOR 27
558577

559578
/* Calls */
560579
#define SPEC_FAIL_CALL_COMPLEX_PARAMETERS 9
@@ -1745,6 +1764,76 @@ _Py_Specialize_CallNoKw(
17451764
return 0;
17461765
}
17471766

1767+
#ifdef Py_STATS
1768+
static int
1769+
binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
1770+
{
1771+
switch (oparg) {
1772+
case NB_ADD:
1773+
case NB_INPLACE_ADD:
1774+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1775+
return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES;
1776+
}
1777+
return SPEC_FAIL_BINARY_OP_ADD_OTHER;
1778+
case NB_AND:
1779+
case NB_INPLACE_AND:
1780+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1781+
return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES;
1782+
}
1783+
if (PyLong_CheckExact(lhs)) {
1784+
return SPEC_FAIL_BINARY_OP_AND_INT;
1785+
}
1786+
return SPEC_FAIL_BINARY_OP_AND_OTHER;
1787+
case NB_FLOOR_DIVIDE:
1788+
case NB_INPLACE_FLOOR_DIVIDE:
1789+
return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
1790+
case NB_LSHIFT:
1791+
case NB_INPLACE_LSHIFT:
1792+
return SPEC_FAIL_BINARY_OP_LSHIFT;
1793+
case NB_MATRIX_MULTIPLY:
1794+
case NB_INPLACE_MATRIX_MULTIPLY:
1795+
return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY;
1796+
case NB_MULTIPLY:
1797+
case NB_INPLACE_MULTIPLY:
1798+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1799+
return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES;
1800+
}
1801+
return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
1802+
case NB_OR:
1803+
case NB_INPLACE_OR:
1804+
return SPEC_FAIL_BINARY_OP_OR;
1805+
case NB_POWER:
1806+
case NB_INPLACE_POWER:
1807+
return SPEC_FAIL_BINARY_OP_POWER;
1808+
case NB_REMAINDER:
1809+
case NB_INPLACE_REMAINDER:
1810+
return SPEC_FAIL_BINARY_OP_REMAINDER;
1811+
case NB_RSHIFT:
1812+
case NB_INPLACE_RSHIFT:
1813+
return SPEC_FAIL_BINARY_OP_RSHIFT;
1814+
case NB_SUBTRACT:
1815+
case NB_INPLACE_SUBTRACT:
1816+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1817+
return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES;
1818+
}
1819+
return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER;
1820+
case NB_TRUE_DIVIDE:
1821+
case NB_INPLACE_TRUE_DIVIDE:
1822+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1823+
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES;
1824+
}
1825+
if (PyFloat_CheckExact(lhs)) {
1826+
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT;
1827+
}
1828+
return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
1829+
case NB_XOR:
1830+
case NB_INPLACE_XOR:
1831+
return SPEC_FAIL_BINARY_OP_XOR;
1832+
}
1833+
Py_UNREACHABLE();
1834+
}
1835+
#endif
1836+
17481837
void
17491838
_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
17501839
SpecializedCacheEntry *cache)
@@ -1754,8 +1843,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
17541843
case NB_ADD:
17551844
case NB_INPLACE_ADD:
17561845
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1757-
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
1758-
goto failure;
1846+
break;
17591847
}
17601848
if (PyUnicode_CheckExact(lhs)) {
17611849
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,
17801868
case NB_MULTIPLY:
17811869
case NB_INPLACE_MULTIPLY:
17821870
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1783-
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
1784-
goto failure;
1871+
break;
17851872
}
17861873
if (PyLong_CheckExact(lhs)) {
17871874
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_INT,
@@ -1797,8 +1884,7 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
17971884
case NB_SUBTRACT:
17981885
case NB_INPLACE_SUBTRACT:
17991886
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1800-
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES);
1801-
goto failure;
1887+
break;
18021888
}
18031889
if (PyLong_CheckExact(lhs)) {
18041890
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT,
@@ -1811,14 +1897,19 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
18111897
goto success;
18121898
}
18131899
break;
1900+
#ifndef Py_STATS
18141901
default:
18151902
// These operators don't have any available specializations. Rather
18161903
// than repeatedly attempting to specialize them, just convert them
1817-
// back to BINARY_OP (while still recording a failure, of course)!
1904+
// back to BINARY_OP (unless we're collecting stats, where it's more
1905+
// important to get accurate hit counts for the unadaptive version
1906+
// and each of the different failure types):
18181907
*instr = _Py_MAKECODEUNIT(BINARY_OP, adaptive->original_oparg);
1908+
return;
1909+
#endif
18191910
}
1820-
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_OTHER);
1821-
failure:
1911+
SPECIALIZATION_FAIL(
1912+
BINARY_OP, binary_op_fail_kind(adaptive->original_oparg, lhs, rhs));
18221913
STAT_INC(BINARY_OP, failure);
18231914
cache_backoff(adaptive);
18241915
return;

0 commit comments

Comments
 (0)