-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
GH-133231: Changes to executor management to support proposed sys._jit
module
#133287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3a2ccda
46ef280
01ecf18
89e4668
2f42cb0
f938d68
a30e444
0b9dcb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1169,6 +1169,17 @@ dummy_func( | |
tstate->current_frame = frame->previous; | ||
assert(!_PyErr_Occurred(tstate)); | ||
PyObject *result = PyStackRef_AsPyObjectSteal(retval); | ||
#if !Py_TAIL_CALL_INTERP | ||
assert(frame == &entry.frame); | ||
#endif | ||
#ifdef _Py_TIER2 | ||
_PyStackRef executor = frame->localsplus[0]; | ||
assert(tstate->current_executor == NULL); | ||
if (!PyStackRef_IsNull(executor)) { | ||
tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); | ||
PyStackRef_CLOSE(executor); | ||
} | ||
#endif | ||
LLTRACE_RESUME_FRAME(); | ||
return result; | ||
} | ||
|
@@ -2912,8 +2923,7 @@ dummy_func( | |
} | ||
else { | ||
this_instr[1].counter = initial_jump_backoff_counter(); | ||
assert(tstate->previous_executor == NULL); | ||
tstate->previous_executor = Py_None; | ||
assert(tstate->current_executor == NULL); | ||
GOTO_TIER_TWO(executor); | ||
} | ||
} | ||
|
@@ -2965,7 +2975,7 @@ dummy_func( | |
assert(executor->vm_data.index == INSTR_OFFSET() - 1); | ||
assert(executor->vm_data.code == code); | ||
assert(executor->vm_data.valid); | ||
assert(tstate->previous_executor == NULL); | ||
assert(tstate->current_executor == NULL); | ||
/* If the eval breaker is set then stay in tier 1. | ||
* This avoids any potentially infinite loops | ||
* involving _RESUME_CHECK */ | ||
|
@@ -2978,8 +2988,6 @@ dummy_func( | |
} | ||
DISPATCH_GOTO(); | ||
} | ||
tstate->previous_executor = Py_None; | ||
Py_INCREF(executor); | ||
GOTO_TIER_TWO(executor); | ||
#else | ||
Py_FatalError("ENTER_EXECUTOR is not supported in this build"); | ||
|
@@ -5254,7 +5262,6 @@ dummy_func( | |
exit->temperature = initial_temperature_backoff_counter(); | ||
Py_CLEAR(exit->executor); | ||
} | ||
tstate->previous_executor = (PyObject *)current_executor; | ||
if (exit->executor == NULL) { | ||
_Py_BackoffCounter temperature = exit->temperature; | ||
if (!backoff_counter_triggers(temperature)) { | ||
|
@@ -5277,7 +5284,6 @@ dummy_func( | |
} | ||
exit->executor = executor; | ||
} | ||
Py_INCREF(exit->executor); | ||
GOTO_TIER_TWO(exit->executor); | ||
} | ||
|
||
|
@@ -5316,7 +5322,6 @@ dummy_func( | |
} | ||
|
||
tier2 op(_START_EXECUTOR, (executor/4 --)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Side note, this instruction now exists solely to set the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can replace all uses of We can also shrink tier2 op(_CHECK_VALIDITY, (validity_ptr/4 --)) {
DEOPT_IF(*validity_ptr == 0);
} For another PR. |
||
Py_CLEAR(tstate->previous_executor); | ||
#ifndef _Py_JIT | ||
current_executor = (_PyExecutorObject*)executor; | ||
#endif | ||
|
@@ -5337,12 +5342,10 @@ dummy_func( | |
} | ||
|
||
tier2 op(_DEOPT, (--)) { | ||
tstate->previous_executor = (PyObject *)current_executor; | ||
GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); | ||
} | ||
|
||
tier2 op(_ERROR_POP_N, (target/2 --)) { | ||
tstate->previous_executor = (PyObject *)current_executor; | ||
assert(oparg == 0); | ||
frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; | ||
SYNC_SP(); | ||
|
@@ -5463,6 +5466,17 @@ dummy_func( | |
if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { | ||
/* Restore previous frame and exit */ | ||
tstate->current_frame = frame->previous; | ||
#if !Py_TAIL_CALL_INTERP | ||
assert(frame == &entry.frame); | ||
#endif | ||
#ifdef _Py_TIER2 | ||
_PyStackRef executor = frame->localsplus[0]; | ||
assert(tstate->current_executor == NULL); | ||
if (!PyStackRef_IsNull(executor)) { | ||
tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); | ||
PyStackRef_CLOSE(executor); | ||
} | ||
#endif | ||
return NULL; | ||
} | ||
next_instr = frame->instr_ptr; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -990,6 +990,11 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) | |
#define DONT_SLP_VECTORIZE | ||
#endif | ||
|
||
typedef struct { | ||
_PyInterpreterFrame frame; | ||
_PyStackRef stack[1]; | ||
} _PyEntryFrame; | ||
Comment on lines
+993
to
+996
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this needed? We only need one slot in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We now need two slots. One on the stack for the return value, as before, and one local variable to hold the current executor. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see. Forgot about the return value. Maybe add a comment that the one stack slot is for the return value, and the one local is for the executor. |
||
|
||
PyObject* _Py_HOT_FUNCTION DONT_SLP_VECTORIZE | ||
_PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) | ||
{ | ||
|
@@ -1009,7 +1014,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int | |
int oparg; /* Current opcode argument, if any */ | ||
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL); | ||
#endif | ||
_PyInterpreterFrame entry_frame; | ||
_PyEntryFrame entry; | ||
|
||
if (_Py_EnterRecursiveCallTstate(tstate, "")) { | ||
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); | ||
|
@@ -1021,30 +1026,37 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int | |
* These are cached values from the frame and code object. */ | ||
_Py_CODEUNIT *next_instr; | ||
_PyStackRef *stack_pointer; | ||
entry_frame.localsplus[0] = PyStackRef_NULL; | ||
entry.stack[0] = PyStackRef_NULL; | ||
brandtbucher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#ifdef Py_STACKREF_DEBUG | ||
entry_frame.f_funcobj = PyStackRef_None; | ||
entry.frame.f_funcobj = PyStackRef_None; | ||
#elif defined(Py_DEBUG) | ||
/* Set these to invalid but identifiable values for debugging. */ | ||
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; | ||
entry_frame.f_locals = (PyObject*)0xaaa1; | ||
entry_frame.frame_obj = (PyFrameObject*)0xaaa2; | ||
entry_frame.f_globals = (PyObject*)0xaaa3; | ||
entry_frame.f_builtins = (PyObject*)0xaaa4; | ||
entry.frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; | ||
entry.frame.f_locals = (PyObject*)0xaaa1; | ||
entry.frame.frame_obj = (PyFrameObject*)0xaaa2; | ||
entry.frame.f_globals = (PyObject*)0xaaa3; | ||
entry.frame.f_builtins = (PyObject*)0xaaa4; | ||
#endif | ||
entry_frame.f_executable = PyStackRef_None; | ||
entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; | ||
entry_frame.stackpointer = entry_frame.localsplus; | ||
entry_frame.owner = FRAME_OWNED_BY_INTERPRETER; | ||
entry_frame.visited = 0; | ||
entry_frame.return_offset = 0; | ||
entry.frame.f_executable = PyStackRef_None; | ||
entry.frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; | ||
entry.frame.stackpointer = entry.stack; | ||
entry.frame.owner = FRAME_OWNED_BY_INTERPRETER; | ||
entry.frame.visited = 0; | ||
entry.frame.return_offset = 0; | ||
#ifdef Py_DEBUG | ||
entry_frame.lltrace = 0; | ||
entry.frame.lltrace = 0; | ||
#endif | ||
/* Push frame */ | ||
entry_frame.previous = tstate->current_frame; | ||
frame->previous = &entry_frame; | ||
entry.frame.previous = tstate->current_frame; | ||
frame->previous = &entry.frame; | ||
tstate->current_frame = frame; | ||
entry.frame.localsplus[0] = PyStackRef_NULL; | ||
brandtbucher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#ifdef _Py_TIER2 | ||
if (tstate->current_executor != NULL) { | ||
entry.frame.localsplus[0] = PyStackRef_FromPyObjectNew(tstate->current_executor); | ||
tstate->current_executor = NULL; | ||
} | ||
#endif | ||
|
||
/* support for generator.throw() */ | ||
if (throwflag) { | ||
|
@@ -1071,9 +1083,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int | |
stack_pointer = _PyFrame_GetStackPointer(frame); | ||
#if Py_TAIL_CALL_INTERP | ||
# if Py_STATS | ||
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0, lastopcode); | ||
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0, lastopcode); | ||
# else | ||
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); | ||
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); | ||
# endif | ||
#else | ||
goto error; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -359,12 +359,12 @@ _PyFrame_SetStackPointer(frame, stack_pointer) | |
do { \ | ||
OPT_STAT_INC(traces_executed); \ | ||
_PyExecutorObject *_executor = (EXECUTOR); \ | ||
tstate->current_executor = (PyObject *)_executor; \ | ||
jit_func jitted = _executor->jit_code; \ | ||
/* Keep the shim frame alive via the executor: */ \ | ||
Py_INCREF(_executor); \ | ||
next_instr = jitted(frame, stack_pointer, tstate); \ | ||
Py_DECREF(_executor); \ | ||
Py_CLEAR(tstate->previous_executor); \ | ||
frame = tstate->current_frame; \ | ||
stack_pointer = _PyFrame_GetStackPointer(frame); \ | ||
if (next_instr == NULL) { \ | ||
|
@@ -377,7 +377,9 @@ do { \ | |
#define GOTO_TIER_TWO(EXECUTOR) \ | ||
do { \ | ||
OPT_STAT_INC(traces_executed); \ | ||
next_uop = (EXECUTOR)->trace; \ | ||
_PyExecutorObject *_executor = (EXECUTOR); \ | ||
tstate->current_executor = (PyObject *)_executor; \ | ||
next_uop = _executor->trace; \ | ||
assert(next_uop->opcode == _START_EXECUTOR); \ | ||
goto enter_tier_two; \ | ||
} while (0) | ||
|
@@ -386,10 +388,11 @@ do { \ | |
#define GOTO_TIER_ONE(TARGET) \ | ||
do \ | ||
{ \ | ||
tstate->current_executor = NULL; \ | ||
next_instr = (TARGET); \ | ||
assert(tstate->current_executor == NULL); \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: this seems redundant, given that we're setting it one line above. |
||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ | ||
_PyFrame_SetStackPointer(frame, stack_pointer); \ | ||
Py_CLEAR(tstate->previous_executor); \ | ||
stack_pointer = _PyFrame_GetStackPointer(frame); \ | ||
if (next_instr == NULL) \ | ||
{ \ | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.