mirror of
https://github.com/python/cpython.git
synced 2025-09-01 14:38:00 +00:00
gh-118335: Configure Tier 2 interpreter at build time (#118339)
The code for Tier 2 is now only compiled when configured with `--enable-experimental-jit[=yes|interpreter]`. We drop support for `PYTHON_UOPS` and -`Xuops`, but you can disable the interpreter or JIT at runtime by setting `PYTHON_JIT=0`. You can also build it without enabling it by default using `--enable-experimental-jit=yes-off`; enable with `PYTHON_JIT=1`. On Windows, the `build.bat` script supports `--experimental-jit`, `--experimental-jit-off`, `--experimental-interpreter`. In the C code, `_Py_JIT` is defined as before when the JIT is enabled; the new variable `_Py_TIER2` is defined when the JIT *or* the interpreter is enabled. It is actually a bitmask: 1: JIT; 2: default-off; 4: interpreter.
This commit is contained in:
parent
9c468e2c5d
commit
7d83f7bcc4
32 changed files with 181 additions and 42 deletions
|
@ -2363,6 +2363,7 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
assert(oparg <= INSTR_OFFSET());
|
||||
JUMPBY(-oparg);
|
||||
#ifdef _Py_TIER2
|
||||
#if ENABLE_SPECIALIZATION
|
||||
_Py_BackoffCounter counter = this_instr[1].counter;
|
||||
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
||||
|
@ -2388,6 +2389,7 @@ dummy_func(
|
|||
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||
}
|
||||
#endif /* ENABLE_SPECIALIZATION */
|
||||
#endif /* _Py_TIER2 */
|
||||
}
|
||||
|
||||
pseudo(JUMP) = {
|
||||
|
@ -2401,6 +2403,7 @@ dummy_func(
|
|||
};
|
||||
|
||||
tier1 inst(ENTER_EXECUTOR, (--)) {
|
||||
#ifdef _Py_TIER2
|
||||
int prevoparg = oparg;
|
||||
CHECK_EVAL_BREAKER();
|
||||
if (this_instr->op.code != ENTER_EXECUTOR ||
|
||||
|
@ -2418,6 +2421,9 @@ dummy_func(
|
|||
tstate->previous_executor = Py_None;
|
||||
Py_INCREF(executor);
|
||||
GOTO_TIER_TWO(executor);
|
||||
#else
|
||||
Py_FatalError("ENTER_EXECUTOR is not supported in this build");
|
||||
#endif /* _Py_TIER2 */
|
||||
}
|
||||
|
||||
replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
|
||||
|
|
|
@ -755,7 +755,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
_Py_CODEUNIT *next_instr;
|
||||
PyObject **stack_pointer;
|
||||
|
||||
#ifndef _Py_JIT
|
||||
#if defined(_Py_TIER2) && !defined(_Py_JIT)
|
||||
/* Tier 2 interpreter state */
|
||||
_PyExecutorObject *current_executor = NULL;
|
||||
const _PyUOpInstruction *next_uop = NULL;
|
||||
|
@ -959,6 +959,7 @@ resume_with_error:
|
|||
goto error;
|
||||
|
||||
|
||||
#ifdef _Py_TIER2
|
||||
|
||||
// Tier 2 is also here!
|
||||
enter_tier_two:
|
||||
|
@ -1113,6 +1114,8 @@ exit_to_trace:
|
|||
|
||||
#endif // _Py_JIT
|
||||
|
||||
#endif // _Py_TIER2
|
||||
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
|
6
Python/generated_cases.c.h
generated
6
Python/generated_cases.c.h
generated
|
@ -2492,6 +2492,7 @@
|
|||
(void)this_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(ENTER_EXECUTOR);
|
||||
#ifdef _Py_TIER2
|
||||
int prevoparg = oparg;
|
||||
CHECK_EVAL_BREAKER();
|
||||
if (this_instr->op.code != ENTER_EXECUTOR ||
|
||||
|
@ -2508,6 +2509,9 @@
|
|||
tstate->previous_executor = Py_None;
|
||||
Py_INCREF(executor);
|
||||
GOTO_TIER_TWO(executor);
|
||||
#else
|
||||
Py_FatalError("ENTER_EXECUTOR is not supported in this build");
|
||||
#endif /* _Py_TIER2 */
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
@ -3432,6 +3436,7 @@
|
|||
CHECK_EVAL_BREAKER();
|
||||
assert(oparg <= INSTR_OFFSET());
|
||||
JUMPBY(-oparg);
|
||||
#ifdef _Py_TIER2
|
||||
#if ENABLE_SPECIALIZATION
|
||||
_Py_BackoffCounter counter = this_instr[1].counter;
|
||||
if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) {
|
||||
|
@ -3457,6 +3462,7 @@
|
|||
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||
}
|
||||
#endif /* ENABLE_SPECIALIZATION */
|
||||
#endif /* _Py_TIER2 */
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
|
|
@ -1705,10 +1705,12 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
|
|||
);
|
||||
return 0;
|
||||
}
|
||||
#ifdef _Py_TIER2
|
||||
if (code->co_executors != NULL) {
|
||||
_PyCode_Clear_Executors(code);
|
||||
}
|
||||
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||
#endif
|
||||
int code_len = (int)Py_SIZE(code);
|
||||
/* Exit early to avoid creating instrumentation
|
||||
* data for potential statically allocated code
|
||||
|
@ -1946,7 +1948,9 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
|
|||
goto done;
|
||||
}
|
||||
set_global_version(tstate, new_version);
|
||||
#ifdef _Py_TIER2
|
||||
_Py_Executors_InvalidateAll(interp, 1);
|
||||
#endif
|
||||
res = instrument_all_executing_code_objects(interp);
|
||||
done:
|
||||
_PyEval_StartTheWorld(interp);
|
||||
|
@ -1986,7 +1990,9 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent
|
|||
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
|
||||
}
|
||||
|
||||
#ifdef _Py_TIER2
|
||||
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||
#endif
|
||||
|
||||
res = instrument_lock_held(code, interp);
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef _Py_TIER2
|
||||
|
||||
#include "Python.h"
|
||||
#include "opcode.h"
|
||||
#include "pycore_interp.h"
|
||||
|
@ -1622,3 +1624,5 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _Py_TIER2 */
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef _Py_TIER2
|
||||
|
||||
/*
|
||||
* This file contains the support code for CPython's uops optimizer.
|
||||
* It also performs some simple optimizations.
|
||||
|
@ -603,3 +605,5 @@ _Py_uop_analyze_and_optimize(
|
|||
OPT_STAT_INC(optimizer_successes);
|
||||
return length;
|
||||
}
|
||||
|
||||
#endif /* _Py_TIER2 */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#ifdef _Py_TIER2
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
|
@ -506,3 +507,5 @@ fail:
|
|||
Py_XDECREF(val_43);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _Py_TIER2 */
|
||||
|
|
|
@ -624,9 +624,11 @@ static int
|
|||
builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
|
||||
{
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
#ifdef _Py_TIER2
|
||||
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
|
||||
_Py_Executors_InvalidateAll(interp, 1);
|
||||
}
|
||||
#endif
|
||||
RARE_EVENT_INTERP_INC(interp, builtin_dict);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1272,30 +1274,30 @@ init_interp_main(PyThreadState *tstate)
|
|||
}
|
||||
|
||||
// Turn on experimental tier 2 (uops-based) optimizer
|
||||
// This is also needed when the JIT is enabled
|
||||
#ifdef _Py_TIER2
|
||||
if (is_main_interp) {
|
||||
#ifndef _Py_JIT
|
||||
// No JIT, maybe use the tier two interpreter:
|
||||
char *envvar = Py_GETENV("PYTHON_UOPS");
|
||||
int enabled = envvar != NULL && *envvar > '0';
|
||||
if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) {
|
||||
enabled = 1;
|
||||
int enabled = 1;
|
||||
#if _Py_TIER2 & 2
|
||||
enabled = 0;
|
||||
#endif
|
||||
char *env = Py_GETENV("PYTHON_JIT");
|
||||
if (env && *env != '\0') {
|
||||
// PYTHON_JIT=0|1 overrides the default
|
||||
enabled = *env != '0';
|
||||
}
|
||||
if (enabled) {
|
||||
#else
|
||||
// Always enable tier two for JIT builds (ignoring the environment
|
||||
// variable and command-line option above):
|
||||
if (true) {
|
||||
#endif
|
||||
PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer();
|
||||
if (opt == NULL) {
|
||||
return _PyStatus_ERR("can't initialize optimizer");
|
||||
}
|
||||
if (PyUnstable_SetOptimizer((_PyOptimizerObject *)opt)) {
|
||||
return _PyStatus_ERR("can't initialize optimizer");
|
||||
return _PyStatus_ERR("can't install optimizer");
|
||||
}
|
||||
Py_DECREF(opt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is_main_interp) {
|
||||
// The main interpreter is handled in Py_Main(), for now.
|
||||
|
@ -1655,10 +1657,12 @@ finalize_modules(PyThreadState *tstate)
|
|||
{
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
|
||||
#ifdef _Py_TIER2
|
||||
// Invalidate all executors and turn off tier 2 optimizer
|
||||
_Py_Executors_InvalidateAll(interp, 0);
|
||||
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
||||
Py_XDECREF(old);
|
||||
#endif
|
||||
|
||||
// Stop watching __builtin__ modifications
|
||||
PyDict_Unwatch(0, interp->builtins);
|
||||
|
|
|
@ -653,8 +653,10 @@ init_interpreter(PyInterpreterState *interp,
|
|||
}
|
||||
interp->sys_profile_initialized = false;
|
||||
interp->sys_trace_initialized = false;
|
||||
#ifdef _Py_TIER2
|
||||
(void)_Py_SetOptimizer(interp, NULL);
|
||||
interp->executor_list_head = NULL;
|
||||
#endif
|
||||
if (interp != &runtime->_main_interpreter) {
|
||||
/* Fix the self-referential, statically initialized fields. */
|
||||
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
|
||||
|
@ -806,9 +808,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
|||
tstate->_status.cleared = 0;
|
||||
}
|
||||
|
||||
#ifdef _Py_TIER2
|
||||
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
||||
assert(old != NULL);
|
||||
Py_DECREF(old);
|
||||
#endif
|
||||
|
||||
/* It is possible that any of the objects below have a finalizer
|
||||
that runs Python code or otherwise relies on a thread state
|
||||
|
@ -2821,9 +2825,11 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp,
|
|||
if (eval_frame == interp->eval_frame) {
|
||||
return;
|
||||
}
|
||||
#ifdef _Py_TIER2
|
||||
if (eval_frame != NULL) {
|
||||
_Py_Executors_InvalidateAll(interp, 1);
|
||||
}
|
||||
#endif
|
||||
RARE_EVENT_INC(set_eval_frame_func);
|
||||
interp->eval_frame = eval_frame;
|
||||
}
|
||||
|
|
|
@ -2165,8 +2165,10 @@ static PyObject *
|
|||
sys__clear_internal_caches_impl(PyObject *module)
|
||||
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
||||
{
|
||||
#ifdef _Py_TIER2
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
_Py_Executors_InvalidateAll(interp, 0);
|
||||
#endif
|
||||
PyType_ClearCache();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue