gh-116381: Remove bad specializations, add fail stats (GH-116464)

* Remove bad specializations, add fail stats
This commit is contained in:
Ken Jin 2024-03-08 00:21:21 +08:00 committed by GitHub
parent 4298d69d4b
commit 41457c7fdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 125 additions and 320 deletions

View file

@ -2238,11 +2238,8 @@ dummy_func(
}
family(CONTAINS_OP, INLINE_CACHE_ENTRIES_CONTAINS_OP) = {
CONTAINS_OP_LIST,
CONTAINS_OP_SET,
CONTAINS_OP_TUPLE,
CONTAINS_OP_DICT,
CONTAINS_OP_STR,
};
op(_CONTAINS_OP, (left, right -- b)) {
@ -2266,46 +2263,25 @@ dummy_func(
macro(CONTAINS_OP) = _SPECIALIZE_CONTAINS_OP + _CONTAINS_OP;
inst(CONTAINS_OP_LIST, (unused/1, left, right -- b)) {
DEOPT_IF(!PyList_CheckExact(right));
int res = _PyList_Contains(right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
inst(CONTAINS_OP_SET, (unused/1, left, right -- b)) {
DEOPT_IF(!PySet_CheckExact(right));
DEOPT_IF(!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right)));
STAT_INC(CONTAINS_OP, hit);
// Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
inst(CONTAINS_OP_TUPLE, (unused/1, left, right -- b)) {
DEOPT_IF(!PyTuple_CheckExact(right));
int res = _PyTuple_Contains((PyTupleObject *)right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
inst(CONTAINS_OP_DICT, (unused/1, left, right -- b)) {
DEOPT_IF(!PyDict_CheckExact(right));
STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
inst(CONTAINS_OP_STR, (unused/1, left, right -- b)) {
DEOPT_IF(!PyUnicode_CheckExact(right));
int res = PyUnicode_Contains(right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
inst(CHECK_EG_MATCH, (exc_value, match_type -- rest, match)) {
if (_PyEval_CheckExceptStarTypeValid(tstate, match_type) < 0) {
DECREF_INPUTS();

View file

@ -2189,24 +2189,6 @@
break;
}
case _CONTAINS_OP_LIST: {
PyObject *right;
PyObject *left;
PyObject *b;
oparg = CURRENT_OPARG();
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyList_CheckExact(right)) goto deoptimize;
int res = _PyList_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error_tier_two;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CONTAINS_OP_SET: {
PyObject *right;
PyObject *left;
@ -2214,7 +2196,9 @@
oparg = CURRENT_OPARG();
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PySet_CheckExact(right)) goto deoptimize;
if (!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right))) goto deoptimize;
STAT_INC(CONTAINS_OP, hit);
// Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
@ -2225,24 +2209,6 @@
break;
}
case _CONTAINS_OP_TUPLE: {
PyObject *right;
PyObject *left;
PyObject *b;
oparg = CURRENT_OPARG();
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyTuple_CheckExact(right)) goto deoptimize;
int res = _PyTuple_Contains((PyTupleObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error_tier_two;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CONTAINS_OP_DICT: {
PyObject *right;
PyObject *left;
@ -2251,6 +2217,7 @@
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyDict_CheckExact(right)) goto deoptimize;
STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
@ -2261,24 +2228,6 @@
break;
}
case _CONTAINS_OP_STR: {
PyObject *right;
PyObject *left;
PyObject *b;
oparg = CURRENT_OPARG();
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyUnicode_CheckExact(right)) goto deoptimize;
int res = PyUnicode_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error_tier_two;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CHECK_EG_MATCH: {
PyObject *match_type;
PyObject *exc_value;

View file

@ -2176,6 +2176,7 @@
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PyDict_CheckExact(right), CONTAINS_OP);
STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
@ -2186,28 +2187,6 @@
DISPATCH();
}
TARGET(CONTAINS_OP_LIST) {
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(CONTAINS_OP_LIST);
static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
PyObject *right;
PyObject *left;
PyObject *b;
/* Skip 1 cache entry */
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PyList_CheckExact(right), CONTAINS_OP);
int res = _PyList_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
DISPATCH();
}
TARGET(CONTAINS_OP_SET) {
frame->instr_ptr = next_instr;
next_instr += 2;
@ -2219,7 +2198,9 @@
/* Skip 1 cache entry */
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PySet_CheckExact(right), CONTAINS_OP);
DEOPT_IF(!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right)), CONTAINS_OP);
STAT_INC(CONTAINS_OP, hit);
// Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
@ -2230,50 +2211,6 @@
DISPATCH();
}
TARGET(CONTAINS_OP_STR) {
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(CONTAINS_OP_STR);
static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
PyObject *right;
PyObject *left;
PyObject *b;
/* Skip 1 cache entry */
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PyUnicode_CheckExact(right), CONTAINS_OP);
int res = PyUnicode_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
DISPATCH();
}
TARGET(CONTAINS_OP_TUPLE) {
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(CONTAINS_OP_TUPLE);
static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
PyObject *right;
PyObject *left;
PyObject *b;
/* Skip 1 cache entry */
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PyTuple_CheckExact(right), CONTAINS_OP);
int res = _PyTuple_Contains((PyTupleObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
if (res < 0) goto pop_2_error;
b = (res ^ oparg) ? Py_True : Py_False;
stack_pointer[-2] = b;
stack_pointer += -1;
DISPATCH();
}
TARGET(CONVERT_VALUE) {
frame->instr_ptr = next_instr;
next_instr += 1;

View file

@ -183,10 +183,7 @@ static void *opcode_targets[256] = {
&&TARGET_COMPARE_OP_INT,
&&TARGET_COMPARE_OP_STR,
&&TARGET_CONTAINS_OP_DICT,
&&TARGET_CONTAINS_OP_LIST,
&&TARGET_CONTAINS_OP_SET,
&&TARGET_CONTAINS_OP_STR,
&&TARGET_CONTAINS_OP_TUPLE,
&&TARGET_FOR_ITER_GEN,
&&TARGET_FOR_ITER_LIST,
&&TARGET_FOR_ITER_RANGE,
@ -235,6 +232,9 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_INSTRUMENTED_RESUME,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_END_SEND,

View file

@ -1218,15 +1218,6 @@
break;
}
case _CONTAINS_OP_LIST: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
if (b == NULL) goto out_of_space;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CONTAINS_OP_SET: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
@ -1236,15 +1227,6 @@
break;
}
case _CONTAINS_OP_TUPLE: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
if (b == NULL) goto out_of_space;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CONTAINS_OP_DICT: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
@ -1254,15 +1236,6 @@
break;
}
case _CONTAINS_OP_STR: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
if (b == NULL) goto out_of_space;
stack_pointer[-2] = b;
stack_pointer += -1;
break;
}
case _CHECK_EG_MATCH: {
_Py_UopsSymbol *rest;
_Py_UopsSymbol *match;

View file

@ -600,6 +600,12 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_TO_BOOL_SET 17
#define SPEC_FAIL_TO_BOOL_TUPLE 18
// CONTAINS_OP
#define SPEC_FAIL_CONTAINS_OP_STR 9
#define SPEC_FAIL_CONTAINS_OP_TUPLE 10
#define SPEC_FAIL_CONTAINS_OP_LIST 11
#define SPEC_FAIL_CONTAINS_OP_USER_CLASS 12
static int function_kind(PyCodeObject *code);
static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
static uint32_t function_get_version(PyObject *o, int opcode);
@ -2562,34 +2568,40 @@ success:
cache->counter = adaptive_counter_cooldown();
}
#ifdef Py_STATS
static int containsop_fail_kind(PyObject *value) {
if (PyUnicode_CheckExact(value)) {
return SPEC_FAIL_CONTAINS_OP_STR;
}
if (PyList_CheckExact(value)) {
return SPEC_FAIL_CONTAINS_OP_LIST;
}
if (PyTuple_CheckExact(value)) {
return SPEC_FAIL_CONTAINS_OP_TUPLE;
}
if (PyType_Check(value)) {
return SPEC_FAIL_CONTAINS_OP_USER_CLASS;
}
return SPEC_FAIL_OTHER;
}
#endif // Py_STATS
void
_Py_Specialize_ContainsOp(PyObject *value, _Py_CODEUNIT *instr)
{
assert(ENABLE_SPECIALIZATION);
assert(_PyOpcode_Caches[CONTAINS_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
_PyContainsOpCache *cache = (_PyContainsOpCache *)(instr + 1);
if (PyUnicode_CheckExact(value)) {
instr->op.code = CONTAINS_OP_STR;
goto success;
}
if (PyList_CheckExact(value)) {
instr->op.code = CONTAINS_OP_LIST;
goto success;
}
if (PyTuple_CheckExact(value)) {
instr->op.code = CONTAINS_OP_TUPLE;
goto success;
}
if (PyDict_CheckExact(value)) {
instr->op.code = CONTAINS_OP_DICT;
goto success;
}
if (PySet_CheckExact(value)) {
if (PySet_CheckExact(value) || PyFrozenSet_CheckExact(value)) {
instr->op.code = CONTAINS_OP_SET;
goto success;
}
SPECIALIZATION_FAIL(CONTAINS_OP, containsop_fail_kind(value));
STAT_INC(CONTAINS_OP, failure);
instr->op.code = CONTAINS_OP;
cache->counter = adaptive_counter_backoff(cache->counter);