[Python-Dev] Pyston: a Python JIT on LLVM

Kevin Modzelewski kmod at dropbox.com
Fri Apr 4 23:57:32 CEST 2014


On Fri, Apr 4, 2014 at 1:59 AM, Antoine Pitrou <solipsis at pitrou.net> wrote:

>
> I'm a bit surprised by the approach. Why don't you simply process CPython
> bytecode, rather than strive to reimplement Python fully?
>

The original choice to operate on Python AST rather than bytecode was made
somewhat arbitrarily, but I think I still support that decision since it
avoids having to do a potentially performance-degrading translation between
a stack language and a register language.  It means we lose the ability to
execute pyc-only distributions, but I suppose that support for that could
be added if it becomes important.

As for why we're building our own runtime as part of all of this (which I
think is what you're getting at), I think that a lot of the performance of
an implementation is caught up in the runtime and isn't just about the AST-
or bytecode- execution.  There are a couple systems out there that will
compile Python to C modules, where all the behavior is implemented using
calls back through the C API.  I haven't tried them, but I'd suspect that
without type information, the gains from doing this aren't that great,
since while you can get rid of bytecode dispatch and perhaps get a better
view of control flow, it doesn't address anything about the dynamic nature
of Python.  For example, in Pyston the fast path for an instance attribute
lookup (with no __getattribute__) will be just two loads: one to lookup the
attribute array and one to load the appropriate offset.  I'd say that it's
necessary to have a different runtime to support that, because it has to be
cooperative and 1) use a different object representation everywhere and 2)
know how to backpatch attribute-lookups to fully take advantage of it.
 That said, we definitely try to not reimplement something if we don't need
to.


> Also, I wonder if it's worthwhile to use a conservative GC, rather than
> reuse the original refcounting scheme (especially since you want to support
> existing extension modules).


I wonder that too :)  The only way to know for sure will be to get it
working on real code, but I feel comfortable with the approach since I
trust that everyone else using GCs are happy and for a reason, and I think
it's possible any GC-related advantages can mask the related
extension-compatibility cost.

I was pretty happy when we switched from refcounting to a tracing GC; the
refcounting was already somewhat optimized (didn't emit any
obviously-duplicate increfs/decrefs), but removing the refcounting
operations opened up a number of other optimizations.  As a simple example,
when refcounting you can't typically do tail call elimination because you
have to do some decrefs() at the end of the function, and those decrefs
will also typically keep the variables live even if they didn't otherwise
need to be.  It was also very hard to tell that certain operations were
no-ops, since even if something is a no-op at the Python level, it can
still do a bunch of refcounting.  You can (and we almost did) write an
optimizer to try to match up all the incref's and decref's, but then you
have to start proving that certain variables remain the same after a
function call, etc....  I'm sure it's possible, but using a GC instead made
all of these optimizations much more natural.



Pyston is definitely far on one side of the effort-vs-potential-payoff
spectrum, and it's certainly fair to say that there are other approaches
that would be less work to implement.  I think that with the wealth of very
impressive existing options, though, it makes sense to take the risky path
and to shoot very high, and I'm fortunate to be in a situation where we can
make a risky bet like that.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20140404/b88b889e/attachment.html>


More information about the Python-Dev mailing list