Introducing Pyston: an upcoming, JIT-based Python implementation

// By Kevin Modzelewski • Apr 03, 2014

Hello everyone, I’m very excited to announce Pyston, a new open-source implementation of Python, currently under development at Dropbox.  The goal of the project is to produce a high-performance Python implementation that can push Python into domains dominated by traditional systems languages like C++.

Here at Dropbox, we love Python and try to use it for as much as we can.  As we scale and the problems we tackle grow, though, we’re starting to find that hitting our performance targets can sometimes become prohibitively difficult when staying on Python.  Sometimes, it can be less work to do a rewrite in another language.  I personally love Python, and it pains me every time we decide to rewrite something, so I wanted to do something about it.  After some abandoned experiments with static compilation, we looked around and saw how successfully JIT techniques are being applied in the JavaScript space: Chrome’s V8 engine, in particular, has greatly pushed the status quo of JavaScript performance.  Our hope is that by using similar techniques, we can achieve similar performance improvements for Python.

Pyston is still in the earliest stages and is not ready for use, but we’re hopeful that by announcing it early in its lifecycle and open-sourcing the code, we can collaborate with the Python and JIT communities throughout its development.  There’s only room for so much detail in this blog post, but we wanted to talk about why we think we need a new Python implementation, and go into a little bit of how Pyston works.

Why a new implementation

There are already a number of Python implementations using JIT techniques, often in sophisticated ways.  PyPy has achieved impressive performance with its tracing JIT; Jython and IronPython are both built on top of mature VMs with extensive JIT support.  So why do we think it’s worth starting a new implementation?

In short, it’s because we think the most promising techniques are incompatible with existing implementations.  For instance, the JavaScript world has switched from tracing JITs to method-at-a-time JITs, due to the compelling performance benefits.  Whether or not the same performance advantage holds for Python is an open question, but since the two approaches are fundamentally incompatible, the only way to start answering the question is to build a new method-at-a-time JIT.

Another point of differentiation is the planned use of a conservative garbage collector to support extension modules efficiently. Again, we won’t know until later whether this is a better approach or not, but it’s a decision that’s integral enough to a JIT that it is difficult to test in an existing implementation.

The downside of starting from scratch is, unsurprisingly, that creating a new language implementation is an enormous task. Luckily, tools are starting to come out that can help with this process; in particular, Pyston is built on top of LLVM, which lets us achieve top-tier code generation quality without having to deal with the details ourselves. Nonetheless, a new Python implementation is a huge undertaking, and Pyston will not be ready for use soon.

How it works

At a high level, Pyston takes parsed Python code and transforms it to the LLVM intermediate representation (IR).  The IR is then run through the LLVM optimizer and passed off to the LLVM JIT engine, resulting in executable machine code.  LLVM contains a large number of optimization passes and mechanisms for easily adding more, which can lead to very fast code.

The problem, though, is that LLVM can’t reason about Python code, because all the low-level behavior is hidden behind the type dispatching you have to do in any dynamic language.  To handle this, Pyston employs type speculation: it is typically impossible to prove that a variable will have a specific type, but Pyston can often predict with some certainty what the type of an object can be.  Once a prediction is made, Pyston will verify the prediction at runtime, branching between a fast path where the prediction holds, and a slow path where it doesn’t.

Pyston also includes other modern techniques such as hidden classes for fast attribute lookups and inline caches for fast method calls.  You can find more technical details on the Github page, along with a separate blog post that goes into more technical detail.

Current state

Pyston is still in its infancy and right now only supports a minimal subset of the Python language.  It’s not quite fair to state benchmark numbers, since 1) Pyston doesn’t support a large enough set of benchmarks to be representative, and 2) Pyston doesn’t support all runtime features (including ones that might introduce slowdowns), so it’s not a true apples-to-apples comparison.  With those caveats, Pyston generally is able to beat CPython’s performance, but still lags behind PyPy.

The code has been released on Github under the Apache 2.0 license, along with a growing amount of technical documentation.  There’s a lot of work to be done, and we’re looking to grow the team: if this kind of thing interests you, please apply!

// Copy link