GH-112354: Initial implementation of warm up on exits and trace-stitching (GH-114142)

This commit is contained in:
Mark Shannon 2024-02-20 09:39:55 +00:00 committed by GitHub
parent acda1757bc
commit 7b21403ccd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 744 additions and 198 deletions

View file

@ -141,7 +141,7 @@
case _TO_BOOL_BOOL: {
PyObject *value;
value = stack_pointer[-1];
if (!PyBool_Check(value)) goto deoptimize;
if (!PyBool_Check(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
break;
}
@ -150,7 +150,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
if (!PyLong_CheckExact(value)) goto deoptimize;
if (!PyLong_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
if (_PyLong_IsZero((PyLongObject *)value)) {
assert(_Py_IsImmortal(value));
@ -168,7 +168,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
if (!PyList_CheckExact(value)) goto deoptimize;
if (!PyList_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
res = Py_SIZE(value) ? Py_True : Py_False;
Py_DECREF(value);
@ -181,7 +181,7 @@
PyObject *res;
value = stack_pointer[-1];
// This one is a bit weird, because we expect *some* failures:
if (!Py_IsNone(value)) goto deoptimize;
if (!Py_IsNone(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
res = Py_False;
stack_pointer[-1] = res;
@ -192,7 +192,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
if (!PyUnicode_CheckExact(value)) goto deoptimize;
if (!PyUnicode_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
if (value == &_Py_STR(empty)) {
assert(_Py_IsImmortal(value));
@ -214,7 +214,7 @@
uint32_t version = (uint32_t)CURRENT_OPERAND();
// This one is a bit weird, because we expect *some* failures:
assert(version);
if (Py_TYPE(value)->tp_version_tag != version) goto deoptimize;
if (Py_TYPE(value)->tp_version_tag != version) goto side_exit;
STAT_INC(TO_BOOL, hit);
Py_DECREF(value);
res = Py_True;
@ -238,8 +238,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyLong_CheckExact(left)) goto deoptimize;
if (!PyLong_CheckExact(right)) goto deoptimize;
if (!PyLong_CheckExact(left)) goto side_exit;
if (!PyLong_CheckExact(right)) goto side_exit;
break;
}
@ -296,8 +296,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyFloat_CheckExact(left)) goto deoptimize;
if (!PyFloat_CheckExact(right)) goto deoptimize;
if (!PyFloat_CheckExact(left)) goto side_exit;
if (!PyFloat_CheckExact(right)) goto side_exit;
break;
}
@ -354,8 +354,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyUnicode_CheckExact(left)) goto deoptimize;
if (!PyUnicode_CheckExact(right)) goto deoptimize;
if (!PyUnicode_CheckExact(left)) goto side_exit;
if (!PyUnicode_CheckExact(right)) goto side_exit;
break;
}
@ -1623,7 +1623,7 @@
uint32_t type_version = (uint32_t)CURRENT_OPERAND();
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
if (tp->tp_version_tag != type_version) goto deoptimize;
if (tp->tp_version_tag != type_version) goto side_exit;
break;
}
@ -2013,8 +2013,6 @@
break;
}
/* _JUMP_BACKWARD is not a viable micro-op for tier 2 */
/* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */
/* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */
@ -3318,7 +3316,7 @@
PyObject *flag;
flag = stack_pointer[-1];
stack_pointer += -1;
if (!Py_IsTrue(flag)) goto deoptimize;
if (!Py_IsTrue(flag)) goto side_exit;
assert(Py_IsTrue(flag));
break;
}
@ -3327,7 +3325,7 @@
PyObject *flag;
flag = stack_pointer[-1];
stack_pointer += -1;
if (!Py_IsFalse(flag)) goto deoptimize;
if (!Py_IsFalse(flag)) goto side_exit;
assert(Py_IsFalse(flag));
break;
}
@ -3338,7 +3336,7 @@
stack_pointer += -1;
if (!Py_IsNone(val)) {
Py_DECREF(val);
if (1) goto deoptimize;
if (1) goto side_exit;
}
break;
}
@ -3347,13 +3345,15 @@
PyObject *val;
val = stack_pointer[-1];
stack_pointer += -1;
if (Py_IsNone(val)) goto deoptimize;
if (Py_IsNone(val)) goto side_exit;
Py_DECREF(val);
break;
}
case _JUMP_TO_TOP: {
next_uop = current_executor->trace;
#ifndef _Py_JIT
next_uop = &current_executor->trace[1];
#endif
CHECK_EVAL_BREAKER();
break;
}
@ -3378,7 +3378,7 @@
case _EXIT_TRACE: {
TIER_TWO_ONLY
if (1) goto deoptimize;
if (1) goto side_exit;
break;
}
@ -3457,6 +3457,60 @@
break;
}
case _COLD_EXIT: {
oparg = CURRENT_OPARG();
TIER_TWO_ONLY
_PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
_PyExitData *exit = &previous->exits[oparg];
exit->temperature++;
PyCodeObject *code = _PyFrame_GetCode(frame);
_Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
if (exit->temperature < (int32_t)tstate->interp->optimizer_side_threshold) {
GOTO_TIER_ONE(target);
}
_PyExecutorObject *executor;
if (target->op.code == ENTER_EXECUTOR) {
executor = code->co_executors->executors[target->op.arg];
Py_INCREF(executor);
} else {
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
if (optimized <= 0) {
int32_t new_temp = -1 * tstate->interp->optimizer_side_threshold;
exit->temperature = (new_temp < INT16_MIN) ? INT16_MIN : new_temp;
if (optimized < 0) {
Py_DECREF(previous);
tstate->previous_executor = Py_None;
if (1) goto error_tier_two;
}
GOTO_TIER_ONE(target);
}
}
/* We need two references. One to store in exit->executor and
* one to keep the executor alive when executing. */
Py_INCREF(executor);
exit->executor = executor;
GOTO_TIER_TWO(executor);
break;
}
case _START_EXECUTOR: {
PyObject *executor = (PyObject *)CURRENT_OPERAND();
TIER_TWO_ONLY
Py_DECREF(tstate->previous_executor);
tstate->previous_executor = NULL;
#ifndef _Py_JIT
current_executor = (_PyExecutorObject*)executor;
#endif
break;
}
case _FATAL_ERROR: {
TIER_TWO_ONLY
assert(0);
Py_FatalError("Fatal error uop executed.");
break;
}
case _CHECK_VALIDITY_AND_SET_IP: {
PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND();
TIER_TWO_ONLY