[Python-checkins] bpo-46072: Add detailed failure stats for BINARY_OP (GH-31289)

brandtbucher webhook-mailer at python.org
Wed Feb 16 11:50:03 EST 2022


https://github.com/python/cpython/commit/580cd9ab2992b7df6f4815020b5841e14a5a6977
commit: 580cd9ab2992b7df6f4815020b5841e14a5a6977
branch: main
author: Brandt Bucher <brandtbucher at microsoft.com>
committer: brandtbucher <brandtbucher at gmail.com>
date: 2022-02-16T08:49:58-08:00
summary:

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

files:
A Misc/NEWS.d/next/Core and Builtins/2022-02-11-13-47-58.bpo-46072.PDS6Ke.rst
M Python/specialize.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-02-11-13-47-58.bpo-46072.PDS6Ke.rst b/Misc/NEWS.d/next/Core and Builtins/2022-02-11-13-47-58.bpo-46072.PDS6Ke.rst
new file mode 100644
index 0000000000000..aa9ea64c129f6
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-02-11-13-47-58.bpo-46072.PDS6Ke.rst	
@@ -0,0 +1 @@
+Add more detailed specialization failure statistics for :opcode:`BINARY_OP`.
diff --git a/Python/specialize.c b/Python/specialize.c
index ab2363cab9f3e..5fd7d0923a698 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -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 */
-
-#define SPEC_FAIL_BINARY_OP_DIFFERENT_TYPES 12
+/* Binary op */
+
+#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;



More information about the Python-checkins mailing list