gh-141504: Refactor policy object into a single opt_config (gh-143644)

This commit is contained in:
Donghee Na 2026-01-15 09:53:00 +09:00 committed by GitHub
parent a73ba4d46e
commit 794f758cd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 89 additions and 64 deletions

View file

@ -1105,7 +1105,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err)
tracer->initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
}
else {
tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&_tstate->policy);
tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&tstate->interp->opt_config);
}
}
else if (tracer->initial_state.executor->vm_data.valid) {
@ -1115,7 +1115,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err)
exit->temperature = restart_backoff_counter(exit->temperature);
}
else {
exit->temperature = initial_temperature_backoff_counter(&_tstate->policy);
exit->temperature = initial_temperature_backoff_counter(&tstate->interp->opt_config);
}
}
Py_CLEAR(tracer->initial_state.code);
@ -1384,9 +1384,10 @@ make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, i
_PyExecutorObject *cold = _PyExecutor_GetColdExecutor();
_PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor();
cold->vm_data.chain_depth = chain_depth;
PyInterpreterState *interp = tstate->base.interp;
for (int i = 0; i < exit_count; i++) {
executor->exits[i].index = i;
executor->exits[i].temperature = initial_temperature_backoff_counter(&tstate->policy);
executor->exits[i].temperature = initial_temperature_backoff_counter(&interp->opt_config);
}
int next_exit = exit_count-1;
_PyUOpInstruction *dest = (_PyUOpInstruction *)&executor->trace[length];

View file

@ -514,6 +514,28 @@ _Py_LazyJitShim(
main interpreter. We fix those fields here, in addition
to the other dynamically initialized fields.
*/
static inline bool
is_env_enabled(const char *env_name)
{
char *env = Py_GETENV(env_name);
return env && *env != '\0' && *env != '0';
}
static inline void
init_policy(uint16_t *target, const char *env_name, uint16_t default_value,
long min_value, long max_value)
{
*target = default_value;
char *env = Py_GETENV(env_name);
if (env && *env != '\0') {
long value = atol(env);
if (value >= min_value && value <= max_value) {
*target = (uint16_t)value;
}
}
}
static PyStatus
init_interpreter(PyInterpreterState *interp,
_PyRuntimeState *runtime, int64_t id,
@ -572,6 +594,31 @@ init_interpreter(PyInterpreterState *interp,
interp->executor_list_head = NULL;
interp->executor_deletion_list_head = NULL;
interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD;
// Initialize optimization configuration from environment variables
// PYTHON_JIT_STRESS sets aggressive defaults for testing, but can be overridden
uint16_t jump_default = JUMP_BACKWARD_INITIAL_VALUE;
uint16_t side_exit_default = SIDE_EXIT_INITIAL_VALUE;
if (is_env_enabled("PYTHON_JIT_STRESS")) {
jump_default = 63;
side_exit_default = 63;
}
init_policy(&interp->opt_config.jump_backward_initial_value,
"PYTHON_JIT_JUMP_BACKWARD_INITIAL_VALUE",
jump_default, 1, MAX_VALUE);
init_policy(&interp->opt_config.jump_backward_initial_backoff,
"PYTHON_JIT_JUMP_BACKWARD_INITIAL_BACKOFF",
JUMP_BACKWARD_INITIAL_BACKOFF, 0, MAX_BACKOFF);
init_policy(&interp->opt_config.side_exit_initial_value,
"PYTHON_JIT_SIDE_EXIT_INITIAL_VALUE",
side_exit_default, 1, MAX_VALUE);
init_policy(&interp->opt_config.side_exit_initial_backoff,
"PYTHON_JIT_SIDE_EXIT_INITIAL_BACKOFF",
SIDE_EXIT_INITIAL_BACKOFF, 0, MAX_BACKOFF);
interp->opt_config.specialization_enabled = !is_env_enabled("PYTHON_SPECIALIZATION_OFF");
if (interp != &runtime->_main_interpreter) {
/* Fix the self-referential, statically initialized fields. */
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
@ -1439,20 +1486,6 @@ decref_threadstate(_PyThreadStateImpl *tstate)
}
}
static inline void
init_policy(uint16_t *target, const char *env_name, uint16_t default_value,
long min_value, long max_value)
{
*target = default_value;
char *env = Py_GETENV(env_name);
if (env && *env != '\0') {
long value = atol(env);
if (value >= min_value && value <= max_value) {
*target = (uint16_t)value;
}
}
}
/* Get the thread state to a minimal consistent state.
Further init happens in pylifecycle.c before it can be used.
All fields not initialized here are expected to be zeroed out,
@ -1538,21 +1571,8 @@ init_threadstate(_PyThreadStateImpl *_tstate,
_tstate->asyncio_running_loop = NULL;
_tstate->asyncio_running_task = NULL;
// Initialize interpreter policy from environment variables
init_policy(&_tstate->policy.interp.jump_backward_initial_value,
"PYTHON_JIT_JUMP_BACKWARD_INITIAL_VALUE",
JUMP_BACKWARD_INITIAL_VALUE, 1, MAX_VALUE);
init_policy(&_tstate->policy.interp.jump_backward_initial_backoff,
"PYTHON_JIT_JUMP_BACKWARD_INITIAL_BACKOFF",
JUMP_BACKWARD_INITIAL_BACKOFF, 0, MAX_BACKOFF);
#ifdef _Py_TIER2
// Initialize JIT policy from environment variables
init_policy(&_tstate->policy.jit.side_exit_initial_value,
"PYTHON_JIT_SIDE_EXIT_INITIAL_VALUE",
SIDE_EXIT_INITIAL_VALUE, 1, MAX_VALUE);
init_policy(&_tstate->policy.jit.side_exit_initial_backoff,
"PYTHON_JIT_SIDE_EXIT_INITIAL_BACKOFF",
SIDE_EXIT_INITIAL_BACKOFF, 0, MAX_BACKOFF);
_tstate->jit_tracer_state = NULL;
#endif
tstate->delete_later = NULL;

View file

@ -48,8 +48,8 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
_Py_BackoffCounter jump_counter, adaptive_counter;
if (enable_counters) {
PyThreadState *tstate = _PyThreadState_GET();
_PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate;
jump_counter = initial_jump_backoff_counter(&tstate_impl->policy);
PyInterpreterState *interp = tstate->interp;
jump_counter = initial_jump_backoff_counter(&interp->opt_config);
adaptive_counter = adaptive_counter_warmup();
}
else {