mirror of https://github.com/python/cpython
GH-118093: Improve handling of short and mid-loop traces (GH-122252)
This commit is contained in:
parent
78df1043db
commit
7797182b78
|
@ -342,8 +342,9 @@ _PyGen_yf(PyGenObject *gen)
|
||||||
{
|
{
|
||||||
if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) {
|
if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) {
|
||||||
_PyInterpreterFrame *frame = &gen->gi_iframe;
|
_PyInterpreterFrame *frame = &gen->gi_iframe;
|
||||||
assert(is_resume(frame->instr_ptr));
|
// GH-122390: These asserts are wrong in the presence of ENTER_EXECUTOR!
|
||||||
assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM);
|
// assert(is_resume(frame->instr_ptr));
|
||||||
|
// assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM);
|
||||||
return PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(frame));
|
return PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(frame));
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -503,8 +503,7 @@ add_to_trace(
|
||||||
if (trace_stack_depth >= TRACE_STACK_SIZE) { \
|
if (trace_stack_depth >= TRACE_STACK_SIZE) { \
|
||||||
DPRINTF(2, "Trace stack overflow\n"); \
|
DPRINTF(2, "Trace stack overflow\n"); \
|
||||||
OPT_STAT_INC(trace_stack_overflow); \
|
OPT_STAT_INC(trace_stack_overflow); \
|
||||||
trace_length = 0; \
|
return 0; \
|
||||||
goto done; \
|
|
||||||
} \
|
} \
|
||||||
assert(func == NULL || func->func_code == (PyObject *)code); \
|
assert(func == NULL || func->func_code == (PyObject *)code); \
|
||||||
trace_stack[trace_stack_depth].func = func; \
|
trace_stack[trace_stack_depth].func = func; \
|
||||||
|
@ -550,6 +549,7 @@ translate_bytecode_to_trace(
|
||||||
} trace_stack[TRACE_STACK_SIZE];
|
} trace_stack[TRACE_STACK_SIZE];
|
||||||
int trace_stack_depth = 0;
|
int trace_stack_depth = 0;
|
||||||
int confidence = CONFIDENCE_RANGE; // Adjusted by branch instructions
|
int confidence = CONFIDENCE_RANGE; // Adjusted by branch instructions
|
||||||
|
bool jump_seen = false;
|
||||||
|
|
||||||
#ifdef Py_DEBUG
|
#ifdef Py_DEBUG
|
||||||
char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
|
char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
|
||||||
|
@ -568,7 +568,6 @@ translate_bytecode_to_trace(
|
||||||
ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)instr, INSTR_IP(instr, code));
|
ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)instr, INSTR_IP(instr, code));
|
||||||
uint32_t target = 0;
|
uint32_t target = 0;
|
||||||
|
|
||||||
top: // Jump here after _PUSH_FRAME or likely branches
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
target = INSTR_IP(instr, code);
|
target = INSTR_IP(instr, code);
|
||||||
// Need space for _DEOPT
|
// Need space for _DEOPT
|
||||||
|
@ -577,6 +576,13 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
||||||
uint32_t opcode = instr->op.code;
|
uint32_t opcode = instr->op.code;
|
||||||
uint32_t oparg = instr->op.arg;
|
uint32_t oparg = instr->op.arg;
|
||||||
|
|
||||||
|
if (!progress_needed && instr == initial_instr) {
|
||||||
|
// We have looped around to the start:
|
||||||
|
RESERVE(1);
|
||||||
|
ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(2, "%d: %s(%d)\n", target, _PyOpcode_OpName[opcode], oparg);
|
DPRINTF(2, "%d: %s(%d)\n", target, _PyOpcode_OpName[opcode], oparg);
|
||||||
|
|
||||||
if (opcode == ENTER_EXECUTOR) {
|
if (opcode == ENTER_EXECUTOR) {
|
||||||
|
@ -603,30 +609,21 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
||||||
/* Special case the first instruction,
|
/* Special case the first instruction,
|
||||||
* so that we can guarantee forward progress */
|
* so that we can guarantee forward progress */
|
||||||
if (progress_needed) {
|
if (progress_needed) {
|
||||||
progress_needed = false;
|
|
||||||
if (opcode == JUMP_BACKWARD || opcode == JUMP_BACKWARD_NO_INTERRUPT) {
|
|
||||||
instr += 1 + _PyOpcode_Caches[opcode] - (int32_t)oparg;
|
|
||||||
initial_instr = instr;
|
|
||||||
if (opcode == JUMP_BACKWARD) {
|
|
||||||
ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) {
|
if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) {
|
||||||
opcode = _PyOpcode_Deopt[opcode];
|
opcode = _PyOpcode_Deopt[opcode];
|
||||||
}
|
}
|
||||||
assert(!OPCODE_HAS_EXIT(opcode));
|
assert(!OPCODE_HAS_EXIT(opcode));
|
||||||
assert(!OPCODE_HAS_DEOPT(opcode));
|
assert(!OPCODE_HAS_DEOPT(opcode));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (OPCODE_HAS_EXIT(opcode)) {
|
if (OPCODE_HAS_EXIT(opcode)) {
|
||||||
// Make space for exit code
|
// Make space for side exit and final _EXIT_TRACE:
|
||||||
|
RESERVE_RAW(2, "_EXIT_TRACE");
|
||||||
max_length--;
|
max_length--;
|
||||||
}
|
}
|
||||||
if (OPCODE_HAS_ERROR(opcode)) {
|
if (OPCODE_HAS_ERROR(opcode)) {
|
||||||
// Make space for error code
|
// Make space for error stub and final _EXIT_TRACE:
|
||||||
|
RESERVE_RAW(2, "_ERROR_POP_N");
|
||||||
max_length--;
|
max_length--;
|
||||||
}
|
}
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
@ -672,20 +669,19 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
||||||
}
|
}
|
||||||
|
|
||||||
case JUMP_BACKWARD:
|
case JUMP_BACKWARD:
|
||||||
|
ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target);
|
||||||
|
_Py_FALLTHROUGH;
|
||||||
case JUMP_BACKWARD_NO_INTERRUPT:
|
case JUMP_BACKWARD_NO_INTERRUPT:
|
||||||
{
|
{
|
||||||
_Py_CODEUNIT *target = instr + 1 + _PyOpcode_Caches[opcode] - (int)oparg;
|
instr += 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] - (int)oparg;
|
||||||
if (target == initial_instr) {
|
if (jump_seen) {
|
||||||
/* We have looped round to the start */
|
|
||||||
RESERVE(1);
|
|
||||||
ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OPT_STAT_INC(inner_loop);
|
OPT_STAT_INC(inner_loop);
|
||||||
DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n");
|
DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n");
|
||||||
}
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
jump_seen = true;
|
||||||
|
goto top;
|
||||||
|
}
|
||||||
|
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
{
|
{
|
||||||
|
@ -904,6 +900,9 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
||||||
assert(instr->op.code == POP_TOP);
|
assert(instr->op.code == POP_TOP);
|
||||||
instr++;
|
instr++;
|
||||||
}
|
}
|
||||||
|
top:
|
||||||
|
// Jump here after _PUSH_FRAME or likely branches.
|
||||||
|
progress_needed = false;
|
||||||
} // End for (;;)
|
} // End for (;;)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -911,16 +910,15 @@ done:
|
||||||
TRACE_STACK_POP();
|
TRACE_STACK_POP();
|
||||||
}
|
}
|
||||||
assert(code == initial_code);
|
assert(code == initial_code);
|
||||||
// Skip short traces like _SET_IP, LOAD_FAST, _SET_IP, _EXIT_TRACE
|
// Skip short traces where we can't even translate a single instruction:
|
||||||
if (progress_needed || trace_length < 5) {
|
if (progress_needed) {
|
||||||
OPT_STAT_INC(trace_too_short);
|
OPT_STAT_INC(trace_too_short);
|
||||||
DPRINTF(2,
|
DPRINTF(2,
|
||||||
"No trace for %s (%s:%d) at byte offset %d (%s)\n",
|
"No trace for %s (%s:%d) at byte offset %d (no progress)\n",
|
||||||
PyUnicode_AsUTF8(code->co_qualname),
|
PyUnicode_AsUTF8(code->co_qualname),
|
||||||
PyUnicode_AsUTF8(code->co_filename),
|
PyUnicode_AsUTF8(code->co_filename),
|
||||||
code->co_firstlineno,
|
code->co_firstlineno,
|
||||||
2 * INSTR_IP(initial_instr, code),
|
2 * INSTR_IP(initial_instr, code));
|
||||||
progress_needed ? "no progress" : "too short");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (trace[trace_length-1].opcode != _JUMP_TO_TOP) {
|
if (trace[trace_length-1].opcode != _JUMP_TO_TOP) {
|
||||||
|
|
Loading…
Reference in New Issue