diff options
author | Guido van Rossum <guido@python.org> | 2024-04-30 18:26:34 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-30 18:26:34 -0700 |
commit | 7d83f7bcc484145596bae1ff015fed0762da345d (patch) | |
tree | f2f3cbb0cefaa920b319c77da00606fef1db48aa /Python | |
parent | 9c468e2c5dffb6fa9811fd16e70fa0463bdfce5f (diff) | |
download | cpython-7d83f7bcc484145596bae1ff015fed0762da345d.tar.gz cpython-7d83f7bcc484145596bae1ff015fed0762da345d.zip |
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.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bytecodes.c | 6 | ||||
-rw-r--r-- | Python/ceval.c | 5 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 6 | ||||
-rw-r--r-- | Python/instrumentation.c | 6 | ||||
-rw-r--r-- | Python/optimizer.c | 4 | ||||
-rw-r--r-- | Python/optimizer_analysis.c | 4 | ||||
-rw-r--r-- | Python/optimizer_symbols.c | 3 | ||||
-rw-r--r-- | Python/pylifecycle.c | 28 | ||||
-rw-r--r-- | Python/pystate.c | 6 | ||||
-rw-r--r-- | Python/sysmodule.c | 2 |
10 files changed, 57 insertions, 13 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 18837aef74d..28766d6d97c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -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 -- )) { diff --git a/Python/ceval.c b/Python/ceval.c index 8b23bc6bcbe..59498bc826e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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__) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1444f5cdebb..602cce4beb1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -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(); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index ce97c3add7d..5614f4867a3 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -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); diff --git a/Python/optimizer.c b/Python/optimizer.c index a9a35fc9020..a5e7430c464 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -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 */ diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 9315d7228b5..842b2e48923 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -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 */ diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 204599b0876..d52f490853c 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1,3 +1,4 @@ +#ifdef _Py_TIER2 #include "Python.h" @@ -506,3 +507,5 @@ fail: Py_XDECREF(val_43); return NULL; } + +#endif /* _Py_TIER2 */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 790398e944f..7726ccc979d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -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); diff --git a/Python/pystate.c b/Python/pystate.c index 9d7b73b3a07..3d6e76e88bd 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -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; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7af363678e8..726051521cf 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -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; } |