mirror of
https://github.com/python/cpython.git
synced 2025-08-26 11:45:20 +00:00
GH-112354: Initial implementation of warm up on exits and trace-stitching (GH-114142)
This commit is contained in:
parent
acda1757bc
commit
7b21403ccd
29 changed files with 744 additions and 198 deletions
96
Python/executor_cases.c.h
generated
96
Python/executor_cases.c.h
generated
|
@ -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 = ¤t_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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue