Introducing Pyston: an upcoming, JIT-based Python implementation

Posted by Kevin Modzelewski on April 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!

Stay tuned for more updates as the project progresses.  If you’d like to subscribe to our announcement mailing list, you can do so here.

  • http://alexgaynor.net/ Alex Gaynor

    Do you really feel like your claim that JS engines moved away from tracing JITs is actually accurate in light of the fact that only Firefox (TraceMonkey) ever used a tracing JIT, and it had a number of well documented flaws; and further, perhaps the most impressive dynamic language JIT, LuaJIT2 is still a tracing JIT?

    • Ryan

      Do you think there is no merit to pursuing alternative ways of JITting python? You think all the engineering effort should go to one project (PyPy) rather than exploring different options?

      • http://veekun.com/ Eevee

        It would certainly be nice to have one incredible JITted Python rather than dividing the effort between two, yes.

        • Trey

          Since PyPy is incompatible with much of the scientific Python stack, this is already a non-starter.

          • http://veekun.com/ Eevee

            But so is Pyston at the moment. Either way someone needs to do the work to fix the compatibility, but now it has to be done twice.

          • http://red-sheep.de flying sheep

            pypy has numpy support. i’m pretty sure pyston doesn’t.

      • TB

        Why start from scratch when there’s a wicket fast Python that already is mature? Seems like a case of “not invented here” mixed with people who don’t want to dig in and learn PyPy.

        • Guest

          Those “people” include Guido van Rossum, the creator of Python and its BDFL, who is now working for Dropbox. I’d be surprised if he didn’t know a thing or two about PyPy.

        • jgmitzen

          PyPy has its own drawbacks and cons. It will be interesting to have a different JIT with its own set of pros and cons. Even if it doesn’t turn out to be faster, it may turn out to suit some people’s use cases more.

      • http://kgriffs.com/ kgriffs

        I don’t see anything wrong with experimenting with some other ideas (for science!), although I think that long term it would be better to combine forces rather than running two separate projects unless there are two fundamentally different use cases that each one is targeting (which right now I don’t think there is).

  • TB

    I’d love to hear more about your issues with PyPy, it sounds like you wrote off PyPy simply because you don’t understand why it works so well. Not to mention that this is mostly a re-hash of stuff found in unladen-swallow.

    I mean, if your end goal is to write another Python, sure go for it. But it really sounds like you people haven’t done their research. I see nothing to write home about.

    • PaulDillinger

      You do know Guido van Rossum works for DropBox now right? If you’re not sure who that is then Google him. He has a nice large Wikipedia page saying that he “is best known as the author of the Python programming language”

      I for one am excited at where this will go. WTG DropBox!

      • http://braintrace.ru Andrey Popp

        Being a creator of Python doesn’t make him automatically knowledgable in how PyPy works.

        • TB

          Or even that he knows the first thing about JIT tech.

    • haydoni

      It says in the post: tracing JITs (pypy) vs method-at-a-time JITs (pyston) are “fundamentally incompatible”.

      This seem to be a completely different approach to LLVM support for pypy (which the pypy team have attempted a few times, so far without success)… the gamble/interesting question is which design choice will lead to better perf in the long run… Dropbox are betting on method-at-a-time JITs!

      • jrk

        That addresses “why not PyPy,” but they totally fail to address “how is this different from Unladen Swallow,” which took exactly this approach just a few years ago and was ultimately unable to achieve much of a performance win while maintaining full compatibility. Among other things, LLVM is a great static compiler, but very slow and high-overhead for a JIT. With dynamic languages, where type speculation often requires regenerating code relatively frequently, this can be an especially big issue.

  • Andrei H

    OSR in LLVM isn’t really supported, it looks like you’re planning to work around it using function calls. Are you planning to add proper OSR support to LLVM in the long-term?

  • mattbillenstein

    Is GvR involved in this project?

    • Kevin Modzelewski

      Guido’s advice has been extremely helpful, but so far we haven’t been able to get any code from him :/

      • mattbillenstein

        What’s his opinion on the overall direction? Where will this succeed where Unladen Swallow failed?

        And best of luck – it’s an ambitious project.

        • Luke Stanley

          Did Unladen Swallow actually fail, or simply not have enough funding / time available?

  • miggitymiggitymiggitymiggity

    I’m aware, as all the naysayers will inexorably point out, that this is a large undertaking and will likely fail… just like every great achievement in history. In other words, bravo to Dropbox for funding this research when they could have just as easily dropped Python for Java, like Twitter did with Ruby, and bravo to you for giving this a shot. I hope it is a huge success. I, for one, have been whining about how Python needs more horsepower to stay afloat with the advent of Go, Node.js, et al, and I’m excited to see somebody working to add horsepower.

  • Wesley Hansen

    Is that pronounced “piston” or “pie-ston” ?

    • Igor Petruk

      Russian speaking community has already started to discuss funny name in their language. At least it is not offensive comparing to “Pidora” a while ago.

      https://www.linux.org.ru/forum/talks/10351478

      • Alexander

        Yep, Russian-speaking people jokingly called Python “piston” for years.

  • George Oblapenko

    I remember reading that PyPy cannot ‘compile’ Python files, i.e. you have to wait each time a Python script. Numba, a LLVM-based JIT compiler for numeric functions will have such an option (I remember using Numba a year ago, and I had to wait 10-15 seconds each time I ran my script before it actually would start doing things and not compile). Will Pyston have the same option?

    • Samuel Giles

      Pretty certain PyPy doesn’t have a wait. (At least it can run pyc files without issue). Definitely not a 10-15 second wait.

      • TB

        Agreed, I’ve never seen much of a wait….if it’s there it’s in the 100-200ms range.

  • Steve

    Didn’t see your position on the GIL. Excised, I hope!

    • jgmitzen

      Threads are evil.

  • Chuck Remes

    There is another platform you could potentially build upon. The Rubinius project has built a Ruby implementation on top of LLVM (per method JIT). Interestingly, it has also been designed as a platform for others to build their own *dynamic* languages on top of this runtime.

    Take a look at http://rubini.us/projects/ for other languages that have been built on top of the Rubinius runtime. Note that there is a (somewhat old, probably bit-rot) Python implementation called Typhon.

    Rubinius has some pretty good corporate support in the form of Enova (a Chicago-based firm). Perhaps there is an opportunity here for DropBox to jump on board a project that has very similar goals and a similar approach with LLVM.

    • Peter Wang

      Some friends of mine who were working on a similar effort also looked at Rubinius and the Shotgun VM, and concluded that if you really want to be pushing performance, VMs really have to become quite tailored for the language they’re running.

      • Chuck Remes

        Interesting history. If they looked at the “shotgun” VM then they were looking at Rubinius probably 3+ years ago. Shotgun was replaced by the current incarnation which is built to utilize LLVM for compiling and JIT.

        It’s probably worth another look now. I love re-inventing the wheel (I do it regularly) but this is an opportunity to short-cut a proof-of-concept. If it pans out, then the decision can be made to start from scratch or continue forward with the rubinius platform.

        Just my 2 cents.

  • Gary Robinson

    I’m wondering if the way you’re planning to handle extension models is compatible with using the existing scipy? The inability to do that has always seemed to me to be a major drawback of PyPy’s approach. If you can use scipy, I’ll be very eager to try Pyston for my statistical work.

  • chip

    Any thoughts on adding optional static typing?

  • skrat

    Talking and comparing to node.js, makes me recall how V8 was originally marketed as being able to support not just JavaScript, but “any” other language. And of course JavaScript is much trickier beast to run than Python is. Did you look into V8 as part of your research?

    • http://www.justcramer.com/ David Cramer

      Why would you say JavaScript is trickier? AFAIK classes in Python are much more complex and harder to support than prototypes/objects in JS.

      • M28

        No. Just no. It’s much harder to optimize for prototype based inheritance than class based.

        • Romain

          you need stuff like sys._getframe() though