#include <assert.h>
#include <stdbool.h>
#include "pycore_structs.h" // _Py_BackoffCounter
+#include "pycore_tstate.h" // _PyPolicy
/* 16-bit countdown counters using exponential backoff.
#define JUMP_BACKWARD_INITIAL_VALUE 4000
#define JUMP_BACKWARD_INITIAL_BACKOFF 6
static inline _Py_BackoffCounter
-initial_jump_backoff_counter(void)
+initial_jump_backoff_counter(_PyPolicy *policy)
{
- return make_backoff_counter(JUMP_BACKWARD_INITIAL_VALUE,
- JUMP_BACKWARD_INITIAL_BACKOFF);
+ return make_backoff_counter(
+ policy->interp.jump_backward_initial_value,
+ policy->interp.jump_backward_initial_backoff);
}
/* Initial exit temperature.
#define SIDE_EXIT_INITIAL_BACKOFF 6
static inline _Py_BackoffCounter
-initial_temperature_backoff_counter(void)
+initial_temperature_backoff_counter(_PyPolicy *policy)
{
- return make_backoff_counter(SIDE_EXIT_INITIAL_VALUE,
- SIDE_EXIT_INITIAL_BACKOFF);
+ return make_backoff_counter(
+ policy->jit.side_exit_initial_value,
+ policy->jit.side_exit_initial_backoff);
}
/* Unreachable backoff counter. */
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
} _PyJitTracerState;
+
#endif
+typedef struct _PyJitPolicy {
+ uint16_t side_exit_initial_value;
+ uint16_t side_exit_initial_backoff;
+} _PyJitPolicy;
+
+typedef struct _PyInterpreterPolicy {
+ uint16_t jump_backward_initial_value;
+ uint16_t jump_backward_initial_backoff;
+} _PyInterpreterPolicy;
+
+typedef struct _PyPolicy {
+ _PyJitPolicy jit;
+ _PyInterpreterPolicy interp;
+} _PyPolicy;
+
// Every PyThreadState is actually allocated as a _PyThreadStateImpl. The
// PyThreadState fields are exposed as part of the C API, although most fields
// are intended to be private. The _PyThreadStateImpl fields not exposed.
#if _Py_TIER2
_PyJitTracerState jit_tracer_state;
#endif
+ _PyPolicy policy;
} _PyThreadStateImpl;
#ifdef __cplusplus
--- /dev/null
+Factor out tracing and optimization heuristics into a single object.
+Patch by Donghee Na.
_tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
}
else {
- _tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter();
+ _tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&_tstate->policy);
}
}
else {
exit->temperature = restart_backoff_counter(exit->temperature);
}
else {
- exit->temperature = initial_temperature_backoff_counter();
+ exit->temperature = initial_temperature_backoff_counter(&_tstate->policy);
}
}
_PyJit_FinalizeTracing(tstate);
}
static _PyExecutorObject *
-make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies, int chain_depth);
+make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies);
static int
uop_optimize(_PyInterpreterFrame *frame, PyThreadState *tstate,
* and not a NOP.
*/
static _PyExecutorObject *
-make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies, int chain_depth)
+make_executor_from_uops(_PyThreadStateImpl *tstate, _PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies)
{
int exit_count = count_exits(buffer, length);
_PyExecutorObject *executor = allocate_executor(exit_count, length);
}
/* Initialize exits */
+ int chain_depth = tstate->jit_tracer_state.initial_state.chain_depth;
_PyExecutorObject *cold = _PyExecutor_GetColdExecutor();
_PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor();
cold->vm_data.chain_depth = chain_depth;
for (int i = 0; i < exit_count; i++) {
executor->exits[i].index = i;
- executor->exits[i].temperature = initial_temperature_backoff_counter();
+ executor->exits[i].temperature = initial_temperature_backoff_counter(&tstate->policy);
}
int next_exit = exit_count-1;
_PyUOpInstruction *dest = (_PyUOpInstruction *)&executor->trace[length];
length = prepare_for_execution(buffer, length);
assert(length <= UOP_MAX_TRACE_LENGTH);
_PyExecutorObject *executor = make_executor_from_uops(
- buffer, length, dependencies, _tstate->jit_tracer_state.initial_state.chain_depth);
+ _tstate, buffer, length, dependencies);
if (executor == NULL) {
return -1;
}
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_audit.h" // _Py_AuditHookEntry
+#include "pycore_backoff.h" // JUMP_BACKWARD_INITIAL_VALUE, SIDE_EXIT_INITIAL_VALUE
#include "pycore_ceval.h" // _PyEval_AcquireLock()
#include "pycore_codecs.h" // _PyCodec_Fini()
#include "pycore_critical_section.h" // _PyCriticalSection_Resume()
}
}
+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,
_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.code_buffer = NULL;
#endif
tstate->delete_later = NULL;
#if ENABLE_SPECIALIZATION_FT
_Py_BackoffCounter jump_counter, adaptive_counter;
if (enable_counters) {
- jump_counter = initial_jump_backoff_counter();
+ PyThreadState *tstate = _PyThreadState_GET();
+ _PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate;
+ jump_counter = initial_jump_backoff_counter(&tstate_impl->policy);
adaptive_counter = adaptive_counter_warmup();
}
else {