diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index d83816ec1502ca..20f6074e13fedd 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1236,6 +1236,16 @@ always available. .. versionadded:: 3.13 +.. function:: _jit_enabled() + + Return :const:`True` if the :ref:`JIT compiler ` is active, + and :const:`False` otherwise. + + Available only in JIT builds; tier 2 interpreter does not count here. + + .. versionadded:: next + + .. function:: is_finalizing() Return :const:`True` if the main Python interpreter is diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b9d2c27eb9a321..f74d5a49dfaf47 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -443,6 +443,9 @@ sys which only exists in specialized builds of Python, may now return objects from other interpreters than the one it's called in. +* Add :func:`sys._jit_enabled` to determine at runtime if the + :ref:`JIT compiler ` is active. + unicodedata ----------- diff --git a/Include/internal/pycore_sysmodule.h b/Include/internal/pycore_sysmodule.h index 99968df54a45f6..f5760a7d8079dc 100644 --- a/Include/internal/pycore_sysmodule.h +++ b/Include/internal/pycore_sysmodule.h @@ -22,6 +22,10 @@ extern int _PySys_ClearAttrString(PyInterpreterState *interp, extern int _PySys_SetFlagObj(Py_ssize_t pos, PyObject *new_value); extern int _PySys_SetIntMaxStrDigits(int maxdigits); +#if defined(_Py_TIER2) && (_Py_TIER2 % 2 != 0) +extern int _PySys_JITEnabled(void); +#endif + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index bf861ef06ee2d3..be3b45ee4fcecd 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1782,10 +1782,8 @@ def test_initconfig_api(self): 'perf_profiling': 2, } config_dev_mode(preconfig, config) - # Temporarily enable ignore_stderr=True to ignore warnings on JIT builds - # See gh-126255 for more information self.check_all_configs("test_initconfig_api", config, preconfig, - api=API_ISOLATED, ignore_stderr=True) + api=API_ISOLATED, env={'PYTHON_JIT': '0'}) def test_initconfig_get_api(self): self.run_embedded_interpreter("test_initconfig_get_api") diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-11-10-04-59-43.gh-issue-126204.ASKDL1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-10-04-59-43.gh-issue-126204.ASKDL1.rst new file mode 100644 index 00000000000000..07e3f4f2f9aca5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-11-10-04-59-43.gh-issue-126204.ASKDL1.rst @@ -0,0 +1 @@ +Allow to determine whether the JIT is enabled at runtime via :func:`sys._jit_enabled`. diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 86c42ceffc5e31..37f62e5f9eca4c 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -1625,6 +1625,38 @@ sys__is_gil_enabled(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +#if defined(_Py_TIER2) && (_Py_TIER2 % 2 != 0) + +PyDoc_STRVAR(sys__jit_enabled__doc__, +"_jit_enabled($module, /)\n" +"--\n" +"\n" +"Returns True if JIT is enabled, False otherwise."); + +#define SYS__JIT_ENABLED_METHODDEF \ + {"_jit_enabled", (PyCFunction)sys__jit_enabled, METH_NOARGS, sys__jit_enabled__doc__}, + +static int +sys__jit_enabled_impl(PyObject *module); + +static PyObject * +sys__jit_enabled(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + int _return_value; + + _return_value = sys__jit_enabled_impl(module); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +#endif /* defined(_Py_TIER2) && (_Py_TIER2 % 2 != 0) */ + #ifndef SYS_GETWINDOWSVERSION_METHODDEF #define SYS_GETWINDOWSVERSION_METHODDEF #endif /* !defined(SYS_GETWINDOWSVERSION_METHODDEF) */ @@ -1668,4 +1700,8 @@ sys__is_gil_enabled(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=6d4f6cd20419b675 input=a9049054013a1b77]*/ + +#ifndef SYS__JIT_ENABLED_METHODDEF + #define SYS__JIT_ENABLED_METHODDEF +#endif /* !defined(SYS__JIT_ENABLED_METHODDEF) */ +/*[clinic end generated code: output=ddccb4b54c4d3e0e input=a9049054013a1b77]*/ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 23882d083844ac..f4090dba20cb3c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1296,43 +1296,34 @@ init_interp_main(PyThreadState *tstate) #endif } - // Turn on experimental tier 2 (uops-based) optimizer - // This is also needed when the JIT is enabled +// Turn on experimental tier 2 (uops-based) optimizer +// This is also needed when the JIT is enabled #ifdef _Py_TIER2 if (is_main_interp) { - 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'; +// perf profiler works fine with tier 2 interpreter, so +// only checking for a "real JIT". +#if _Py_TIER % 2 != 0 + if (_PySys_JITEnabled() && config->perf_profiling > 0) { + (void)PyErr_WarnEx( + PyExc_RuntimeWarning, + "JIT deactivated as perf profiling support is active", + 0); } - if (enabled) { -#ifdef _Py_JIT - // perf profiler works fine with tier 2 interpreter, so - // only checking for a "real JIT". - if (config->perf_profiling > 0) { - (void)PyErr_WarnEx( - PyExc_RuntimeWarning, - "JIT deactivated as perf profiling support is active", - 0); - } else + else #endif - { - PyObject *opt = _PyOptimizer_NewUOpOptimizer(); - if (opt == NULL) { - return _PyStatus_ERR("can't initialize optimizer"); - } - if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { - return _PyStatus_ERR("can't install optimizer"); - } + { + PyObject *opt = _PyOptimizer_NewUOpOptimizer(); + if (opt == NULL) { + return _PyStatus_ERR("can't initialize optimizer"); + } + if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { Py_DECREF(opt); + return _PyStatus_ERR("can't install optimizer"); } + Py_DECREF(opt); } } -#endif +#endif // Py_TIER2 if (!is_main_interp) { // The main interpreter is handled in Py_Main(), for now. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index aaef5aa532412b..0589d1a24ca93f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2264,12 +2264,14 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) /*[clinic end generated code: output=5783cdeb51874b43 input=a12df928758a82b4]*/ { #ifdef PY_HAVE_PERF_TRAMPOLINE -#ifdef _Py_JIT - _PyOptimizerObject* optimizer = _Py_GetOptimizer(); - if (optimizer != NULL) { - Py_DECREF(optimizer); - PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); - return NULL; +#if defined(_Py_TIER2) && (_Py_TIER2 % 2 != 0) + if (_PySys_JITEnabled()) { + _PyOptimizerObject *optimizer = _Py_GetOptimizer(); + if (optimizer != NULL) { + Py_DECREF(optimizer); + PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); + return NULL; + } } #endif @@ -2533,6 +2535,46 @@ PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename) { } +#ifdef _Py_TIER2 +// _Py_TIER2 is set to 4 or 6 in tier 2 builds. +#if _Py_TIER2 % 2 != 0 +int +_PySys_JITEnabled(void) +{ + const char *env = Py_GETENV("PYTHON_JIT"); + if (_Py_TIER2 == 1) { + // Interpreter was built with enabled jit, but it can be disabled via PYTHON_JIT=0 + if (env && *env != '\0') { + return *env != '0'; + } + return 1; + } + else if (_Py_TIER2 == 3) { + // Interpreter was built with disabled jit, but it can be enabled via PYTHON_JIT=1 + if (env && *env != '\0') { + return *env == '1'; + } + return 0; + } + Py_UNREACHABLE(); +} + +/*[clinic input] +sys._jit_enabled -> bool + +Returns True if JIT is enabled, False otherwise. +[clinic start generated code]*/ + +static int +sys__jit_enabled_impl(PyObject *module) +/*[clinic end generated code: output=e8adca3fa5011880 input=f2bdfa820c11f65b]*/ +{ + return _PySys_JITEnabled(); +} +#endif +#endif // _Py_TIER2 + + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ SYS_ADDAUDITHOOK_METHODDEF @@ -2603,6 +2645,7 @@ static PyMethodDef sys_methods[] = { #endif SYS__GET_CPU_COUNT_CONFIG_METHODDEF SYS__IS_GIL_ENABLED_METHODDEF + SYS__JIT_ENABLED_METHODDEF {NULL, NULL} // sentinel };