8000 gh-118335: Configure Tier 2 interpreter at build time (#118339) · python/cpython@7d83f7b · GitHub
[go: up one dir, main page]

Skip to content

Commit 7d83f7b

Browse files
authored
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.
1 parent 9c468e2 commit 7d83f7b

32 files changed

+181
-42
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ Experimental JIT Compiler
888888
=========================
889889

890890
When CPython is configured using the ``--enable-experimental-jit`` option,
891-
a just-in-time compiler is added which can speed up some Python programs.
891+
a just-in-time compiler is added which may speed up some Python programs.
892892

893893
The internal architecture is roughly as follows.
894894

@@ -905,19 +905,35 @@ The internal architecture is roughly as follows.
905905
before it is interpreted or translated to machine code.
906906

907907
* There is a Tier 2 interpreter, but it is mostly intended for debugging
908-
the earlier stages of the optimization pipeline. If the JIT is not
909-
enabled, the Tier 2 interpreter can be invoked by passing Python the
910-
``-X uops`` option or by setting the ``PYTHON_UOPS`` environment
911-
variable to ``1``.
908+
the earlier stages of the optimization pipeline.
909+
The Tier 2 interpreter can be enabled by configuring Python
910+
with ``--enable-experimental-jit=interpreter``.
912911

913-
* When the ``--enable-experimental-jit`` option is used, the optimized
912+
* When the JIT is enabled, the optimized
914913
Tier 2 IR is translated to machine code, which is then executed.
915-
This does not require additional runtime options.
916914

917915
* The machine code translation process uses an architecture called
918916
*copy-and-patch*. It has no runtime dependencies, but there is a new
919917
build-time dependency on LLVM.
920918

919+
The ``--enable-experimental-jit`` flag has the following optional values:
920+
921+
* ``no`` (default) -- Disable the entire Tier 2 and JIT pipeline.
922+
923+
* ``yes`` (default if the flag is present without optional value)
924+
-- Enable the JIT. To disable the JIT at runtime,
925+
pass the environment variable ``PYTHON_JIT=0``.
926+
927+
* ``yes-off`` -- Build the JIT but disable it by default.
928+
To enable the JIT at runtime, pass the environment variable
929+
``PYTHON_JIT=1``.
930+
931+
* ``interpreter`` -- Enable the Tier 2 interpreter but disable the JIT.
932+
The interpreter can be disabled by running with
933+
``PYTHON_JIT=0``.
934+
935+
(On Windows, use ``PCbuild/build.bat --enable-jit`` to enable the JIT.)
936+
921937
See :pep:`744` for more details.
922938

923939
(JIT by Brandt Bucher, inspired by a paper by Haoran Xu and Fredrik Kjolstad.

Include/internal/pycore_opcode_metadata.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/dis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def _get_code_array(co, adaptive):
216216
if op == ENTER_EXECUTOR:
217217
try:
218218
ex = get_executor(co, i)
219-
except ValueError:
219+
except (ValueError, RuntimeError):
220220
ex = None
221221

222222
if ex:

Lib/test/support/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,17 +2539,17 @@ def exceeds_recursion_limit():
25392539
# Decorator to disable optimizer while a function run
25402540
def without_optimizer(func):
25412541
try:
2542-
import _testinternalcapi
2542+
from _testinternalcapi import get_optimizer, set_optimizer
25432543
except ImportError:
25442544
return func
25452545
@functools.wraps(func)
25462546
def wrapper(*args, **kwargs):
2547-
save_opt = _testinternalcapi.get_optimizer()
2547+
save_opt = get_optimizer()
25482548
try:
2549-
_testinternalcapi.set_optimizer(None)
2549+
set_optimizer(None)
25502550
return func(*args, **kwargs)
25512551
finally:
2552-
_testinternalcapi.set_optimizer(save_opt)
2552+
set_optimizer(save_opt)
25532553
return wrapper
25542554

25552555

Lib/test/test_capi/test_opt.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def clear_executors(func):
3434

3535

3636
@requires_specialization
37+
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
38+
"Requires optimizer infrastructure")
3739
class TestOptimizerAPI(unittest.TestCase):
3840

3941
def test_new_counter_optimizer_dealloc(self):
@@ -136,6 +138,8 @@ def get_opnames(ex):
136138

137139

138140
@requires_specialization
141+
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
142+
"Requires optimizer infrastructure")
139143
class TestExecutorInvalidation(unittest.TestCase):
140144

141145
def setUp(self):
@@ -215,6 +219,8 @@ def f():
215219

216220

217221
@requires_specialization
222+
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
223+
"Requires optimizer infrastructure")
218224
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
219225
class TestUops(unittest.TestCase):
220226

@@ -579,6 +585,8 @@ def testfunc(n):
579585

580586

581587
@requires_specialization
588+
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
589+
"Requires optimizer infrastructure")
582590
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
583591
class TestUopsOptimization(unittest.TestCase):
584592

Lib/test/test_monitoring.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,15 +1831,17 @@ class TestOptimizer(MonitoringTestBase, unittest.TestCase):
18311831

18321832
def setUp(self):
18331833
_testinternalcapi = import_module("_testinternalcapi")
1834-
self.old_opt = _testinternalcapi.get_optimizer()
1835-
opt = _testinternalcapi.new_counter_optimizer()
1836-
_testinternalcapi.set_optimizer(opt)
1834+
if hasattr(_testinternalcapi, "get_optimizer"):
1835+
self.old_opt = _testinternalcapi.get_optimizer()
1836+
opt = _testinternalcapi.new_counter_optimizer()
1837+
_testinternalcapi.set_optimizer(opt)
18371838
super(TestOptimizer, self).setUp()
18381839

18391840
def tearDown(self):
18401841
super(TestOptimizer, self).tearDown()
18411842
import _testinternalcapi
1842-
_testinternalcapi.set_optimizer(self.old_opt)
1843+
if hasattr(_testinternalcapi, "get_optimizer"):
1844+
_testinternalcapi.set_optimizer(self.old_opt)
18431845

18441846
def test_for_loop(self):
18451847
def test_func(x):

Lib/test/test_opcache.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
def disabling_optimizer(func):
1818
def wrapper(*args, **kwargs):
19+
if not hasattr(_testinternalcapi, "get_optimizer"):
20+
return func(*args, **kwargs)
1921
old_opt = _testinternalcapi.get_optimizer()
2022
_testinternalcapi.set_optimizer(None)
2123
try:

Lib/test/test_optimizer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ def func(x=0):
8080

8181
class TestOptimizerSymbols(unittest.TestCase):
8282

83+
@unittest.skipUnless(hasattr(_testinternalcapi, "uop_symbols_test"),
84+
"requires _testinternalcapi.uop_symbols_test")
8385
def test_optimizer_symbols(self):
8486
_testinternalcapi.uop_symbols_test()
8587

Lib/test/test_weakref.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from test.support import gc_collect
1818
from test.support import import_helper
1919
from test.support import threading_helper
20+
from test.support import is_wasi, Py_DEBUG
2021

2122
# Used in ReferencesTestCase.test_ref_created_during_del() .
2223
ref_from_del = None
@@ -960,6 +961,7 @@ def test_hashing(self):
960961
self.assertEqual(hash(a), hash(42))
961962
self.assertRaises(TypeError, hash, b)
962963

964+
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
963965
def test_trashcan_16602(self):
964966
# Issue #16602: when a weakref's target was part of a long
965967
# deallocation chain, the trashcan mechanism could delay clearing

0 commit comments

Comments
 (0)
0