Skip to content

Commit 6045a67

Browse files
Specialize on deopt when tracing
1 parent 754b3b7 commit 6045a67

File tree

5 files changed

+58
-17
lines changed

5 files changed

+58
-17
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ typedef struct _PyJitState {
765765
_PyUOpInstruction *jit_tracer_code_buffer;
766766
_Py_CODEUNIT *jit_tracer_insert_exec_instr;
767767
_Py_CODEUNIT *jit_tracer_close_loop_instr;
768+
_Py_CODEUNIT *last_specialized_instr;
768769
int jit_tracer_initial_stack_depth;
769770
int jit_tracer_initial_chain_depth;
770771
PyCodeObject *jit_tracer_initial_code; // Strong

Python/ceval_macros.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@
137137

138138
#if _Py_TAIL_CALL_INTERP || USE_COMPUTED_GOTOS
139139
# define IS_JIT_TRACING() (DISPATCH_TABLE_VAR == TRACING_DISPATCH_TABLE)
140+
// tstate->interp->jit_state.last_specialized_instr != this_instr is required to not get stuck in infinite
141+
// specialization loops due to specialization failure.
142+
# define IS_JIT_TRACING_MAKING_PROGRESS() (IS_JIT_TRACING() && tstate->interp->jit_state.last_specialized_instr != this_instr)
140143
# define ENTER_TRACING() \
141144
DISPATCH_TABLE_VAR = TRACING_DISPATCH_TABLE;
142145
# define LEAVE_TRACING() \
@@ -214,6 +217,14 @@ do { \
214217
DISPATCH_GOTO(); \
215218
}
216219

220+
#define TRACING_SPECIALIZE_DISPATCH_SAME_OPARG() \
221+
{ \
222+
tstate->interp->jit_state.last_specialized_instr = this_instr; \
223+
opcode = next_instr->op.code; \
224+
PRE_DISPATCH_GOTO(); \
225+
DISPATCH_GOTO(); \
226+
}
227+
217228
#define DISPATCH_INLINED(NEW_FRAME) \
218229
do { \
219230
assert(tstate->interp->eval_frame == NULL); \
@@ -225,11 +236,13 @@ do { \
225236
} while (0)
226237

227238
#define TRACING_DISPATCH_INLINED(NEW_FRAME) \
239+
tstate->interp->jit_state.last_specialized_instr = this_instr; \
228240
RECORD_TRACE_NO_DISPATCH(); \
229241
DISPATCH_INLINED(NEW_FRAME);
230242

231243
#define TRACING_DISPATCH() \
232244
{ \
245+
tstate->interp->jit_state.last_specialized_instr = this_instr; \
233246
assert(frame->stackpointer == NULL); \
234247
RECORD_TRACE_NO_DISPATCH(); \
235248
NEXTOPARG(); \
@@ -337,9 +350,14 @@ GETITEM(PyObject *v, Py_ssize_t i) {
337350
/* This takes a uint16_t instead of a _Py_BackoffCounter,
338351
* because it is used directly on the cache entry in generated code,
339352
* which is always an integral type. */
353+
#if _Py_TIER2
354+
// Force re-specialization when tracing a side exit to get good side exits.
355+
#define ADAPTIVE_COUNTER_TRIGGERS(COUNTER) \
356+
backoff_counter_triggers(forge_backoff_counter((COUNTER))) || IS_JIT_TRACING_MAKING_PROGRESS()
357+
#else
340358
#define ADAPTIVE_COUNTER_TRIGGERS(COUNTER) \
341359
backoff_counter_triggers(forge_backoff_counter((COUNTER)))
342-
360+
#endif
343361
#define ADVANCE_ADAPTIVE_COUNTER(COUNTER) \
344362
do { \
345363
(COUNTER) = advance_backoff_counter((COUNTER)); \

Python/generated_tracer_cases.c.h

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,9 +904,10 @@ _PyJIT_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_
904904
tstate->interp->jit_state.jit_tracer_previous_exit = exit;
905905
_Py_BloomFilter_Init(&tstate->interp->jit_state.jit_tracer_dependencies);
906906
tstate->interp->jit_state.jit_tracer_initial_stack_depth = curr_stackdepth;
907-
tstate->interp->jit_state.jit_tracer_initial_chain_depth = chain_depth;
907+
tstate->interp->jit_state.jit_tracer_initial_chain_depth = chain_depth % MAX_CHAIN_DEPTH;
908908
tstate->interp->jit_state.jit_tracer_current_frame = frame;
909909
tstate->interp->jit_state.jit_tracer_dependencies_still_valid = true;
910+
tstate->interp->jit_state.last_specialized_instr = NULL;
910911
}
911912

912913
void

Tools/cases_generator/tracer_generator.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool =
4444
**self._replacers,
4545
"DISPATCH": self.dispatch,
4646
"DISPATCH_INLINED": self.dispatch_inlined,
47+
"DISPATCH_SAME_OPARG": self.dispatch_same_oparg,
4748
}
4849

4950
def dispatch(
@@ -75,6 +76,26 @@ def dispatch_inlined(
7576
self.out.start_line()
7677
self.emit("TRACING_DISPATCH_INLINED")
7778
return False
79+
80+
def dispatch_same_oparg(
81+
self,
82+
tkn: Token,
83+
tkn_iter: TokenIterator,
84+
uop: CodeSection,
85+
storage: Storage,
86+
inst: Instruction | None,
87+
) -> bool:
88+
if storage.spilled:
89+
raise analysis_error("stack_pointer needs reloading before dispatch", tkn)
90+
storage.stack.flush(self.out)
91+
self.out.start_line()
92+
if "specializing" in uop.annotations:
93+
self.emit("TRACING_SPECIALIZE_DISPATCH_SAME_OPARG")
94+
else:
95+
self.emit(tkn)
96+
emit_to(self.out, tkn_iter, "SEMI")
97+
return False
98+
7899
def record_jump_taken(
79100
self,
80101
tkn: Token,

0 commit comments

Comments
 (0)