How Python 3.15 Watches Itself Run, For Almost Free
To make Python faster, its new compiler watches the interpreter run. But watching a running program normally slows the thing you measure. This one barely does.
Its new JIT records the interpreter, then compiles the path.
running
instruction stream
Python 3.15 ships an experimental compiler. To know what to compile, it records the exact stream of instructions the interpreter runs. But recording means watching every instruction. And the watcher has to stay cheap.
Three ways to watch. Two of them are too slow.
There are three ways to build that watcher. The first two are too slow. One runs a second interpreter beside the normal one, costing about six percent. The other checks every instruction. Both grow the hot loop, and it has to stay small.
Keep two dispatch tables. Swap one pointer.
# define ENTER_TRACING() \ DISPATCH_TABLE_VAR = TRACING_DISPATCH_TABLE; # define LEAVE_TRACING() \ DISPATCH_TABLE_VAR = DISPATCH_TABLE;
Here's the third way. An interpreter picks where to go next by looking each instruction up in a table of addresses. Keep two tables. One variable says which is live. So switching modes is one pointer swap, with no branch on any instruction. Now the clever part. Every instruction in the profiling table points at one recorder. It logs the step, then dispatches through the normal table to the real handler. Off, the interpreter runs as before. Turning it on, or off, is one line.
On a toy benchmark: at most 4.5× — profiling and compiling together.
On a toy benchmark, profiling and compiling together ran at most four and a half times slower than the plain interpreter. That cost is real, but small, and only while recording. The switch itself is free.
The cost didn't vanish. It moved.
The runtime cost nearly vanished. But it did not disappear. It moved. The interpreter now carries two dispatch tables and a fan-in for a person to keep straight. The author calls it elegant, and hard to reason about.
When you must watch every step, do not check at every step.
The lesson has nothing to do with Python. When you must watch every step, do not check at every step. Swap the rulebook. Route every step through one watcher.


















