Python 3.15 sharpens the experimental Just-In-Time (JIT) compiler. It adds a new tracing frontend, basic register allocation, in-place int and float operations, tighter machine code, and more. In this tutorial, you’ll learn how to enable and benchmark the 3.15 JIT on your own machine and explore what makes it faster.
By the end of this tutorial, you’ll understand that:
- Python 3.15 improved the experimental JIT compiler that you opt into with
PYTHON_JIT=1. - The new tracing frontend records actual bytecode paths instead of estimating them, and the optimizer covers a wider set of operations.
- Basic register allocation and tighter codegen reduce stack traffic and memory use.
- Reference-count elimination and in-place ops speed up float-heavy numeric loops.
- The official
pyperformancesuite reports an 8–9 percent geometric mean speedup on x86-64 Linux.
First, you’ll set up a Python 3.15 build with the JIT compiled in and run a quick benchmark to see the speedup on your own machine. Then you’ll walk through each optimizer upgrade and verify the numbers against the official pyperformance suite. The JIT is still experimental, so treat the numbers as a snapshot of where things stood in the 3.15 beta rather than a guarantee for the final release.
Get Your Code: Click here to download the free sample code you’ll use to benchmark the JIT and measure the speedup on your own machine.
Set Up a Python 3.15 Build With the JIT Compiler
To follow along, you’ll need a pre-release of Python 3.15 with the JIT compiled in. At the time of this writing, the latest pre-release is 3.15.0b2. Once you have a JIT-capable build, you’ll opt into the JIT at runtime by setting the PYTHON_JIT environment variable to 1.
The JIT has shipped in the official Python installer on Windows and macOS since Python 3.14, so the Windows and macOS installers from python.org include it without any manual configuration step.
A handy path to a JIT-capable build is to use pyenv, which accepts the JIT configure flag through an environment variable. If you have pyenv installed, then you can run the following commands:
$ export PYTHON_CONFIGURE_OPTS="--enable-experimental-jit=yes-off"
$ pyenv install 3.15.0b2
With these commands, pyenv builds and installs Python 3.15.0b2 with the JIT included but switched off by default with the yes-off value. You can enable the JIT manually with PYTHON_JIT=1. If you’ve never installed a Python pre-release before, the guide How Can You Install a Pre-Release Version of Python? can walk you through the process.
Note: If you’d rather build CPython yourself, then you can pass --enable-experimental-jit=yes-off directly to ./configure and run make:
$ ./configure --enable-experimental-jit=yes-off
$ make -j
You’ll need a matching version of the LLVM compiler infrastructure installed locally because the build uses it to generate JIT stencils. The 3.15 build pins to LLVM 21.
With the 3.15.0b2 build in place, you can confirm that the JIT is active by checking sys._jit.is_enabled() with and without PYTHON_JIT set:
$ pyenv shell 3.15.0b2
$ python -c "import sys; print(sys._jit.is_enabled())"
False
$ PYTHON_JIT=1 python -c "import sys; print(sys._jit.is_enabled())"
True
In this example, you run the same one-liner twice—once without the environment variable and once with it. The sys._jit namespace is an experimental implementation detail signaled by the leading underscore, and it may change between minor releases. Treat any code that reads it as throwaway debugging code rather than production introspection.
If the command with PYTHON_JIT=1 still prints False, then the JIT wasn’t compiled into this build. Recheck your configure flags or fall back to the python.org installer.
Before you spend time building 3.15, it’s worth knowing that the JIT’s long-term future is under active discussion: the Python Steering Council recently paused new JIT development. The compiler still ships in 3.15 and keeps receiving bug and security fixes, and you’ll find the full story in Decide Whether to Enable the JIT at the end of this tutorial.
Run a Quick JIT Benchmark
Before diving into what’s new in 3.15’s JIT, you can see the speedup in action. The following quick_bench.py script runs a tight, float-heavy loop wrapped in timeit, then prints whether the JIT was enabled and the average execution time per repeat:
quick_bench.py
"""Quick benchmark: compare CPython 3.15 with the JIT off vs on.
Run twice against the same 3.15 build and compare the two timings:
PYTHON_JIT=0 python quick_bench.py
PYTHON_JIT=1 python quick_bench.py
"""
import sys
from timeit import timeit
ITERATIONS = 20_000_000
REPEATS = 5
def workload():
x = 1.0
for _ in range(ITERATIONS):
x = x * 1.0001
return x
def jit_enabled():
jit = getattr(sys, "_jit", None)
return bool(jit and jit.is_enabled())
def main():
seconds = timeit(workload, number=REPEATS) / REPEATS
label = "JIT on" if jit_enabled() else "JIT off"
print(f"{label}: {seconds:.2f} s")
if __name__ == "__main__":
main()
In this script, you wrap workload() in timeit() and average across REPEATS runs. The function is intentionally minimal and runs a tight loop that multiplies a float by a small constant. That operation is where the new JIT’s float optimization pays off, because the JIT can reuse the same float object across iterations instead of allocating a fresh one each time.
Note: A tight loop is a loop that performs minimal work on each pass and carries almost no overhead between iterations. The CPU spends nearly all its time running the loop body over and over.
You can run the script twice against the same Python 3.15 build, toggling PYTHON_JIT each time:
$ PYTHON_JIT=0 python quick_bench.py
JIT off: 1.54 s
$ PYTHON_JIT=1 python quick_bench.py
JIT on: 0.96 s
You have two numbers from the same machine and the same build: JIT off versus JIT on. In this example, dividing 1.54 by 0.96 gives about 1.6, so the JIT-on run is roughly 1.6 times faster than the JIT-off one. Cool!


