From what I understand, Julia doesn’t do any tracing at all, it just compiles each function based on the types it receives. Obviously Python doesn’t have multiple dispatch, but that actually might make compilation easier. Swap out the LLVM step with python's IR and they could probably expect a pretty substantial performance improvement. That said I don’t know anything about compilers, I just use both Python and Julia.
This is called a method based JIT, and is generally the more common approach to JIT compilation. Tracing JIT is a deliberate design choice that is quite different from method based JITs
(author of the blog post here)
"just compile when you know the types" is not a good strategy for Python.
My EuroPython talk "Myths and fairy tales about Python performance" explains many reasons why Python is VERY hard to optimize: https://lwn.net/Articles/1031707/
One big advantage of tracing JITs is that they are generally easier to write an to maintain.
For the specific case of PyPy, it's actually a "meta tracing JIT": you trace the interpreter, not the underlying program, which TL;DR means that you can write the interpreter (which is "easy") and you get a JIT compiler for free.
The basic assumption of a tracing JIT is that you have one or more "hot loops" in which you have one (or few) fast paths which are taken most of the time.
If the assumption holds, tracing has big advantages because you eliminate most of dynamism and you automatically inline across multiple layer of function calls, which in turns make it possible to eliminate allocation of most temporary objects.
The problem is that the assumption not always holds, and that's where you start to get problems.
But methods JITs are not THE solution either. Meta has a whole team developing Cinder, which is a method JIT for Python, but they had to introduce what they call "static python", which is an opt-in sets of constraints to remove some Python dynamism to make the JIT job easier.
Finally, as soon as you call any C extension, any JIT is out of luck and must deoptimize to present a "state of the world" which is compatible with that the C extension finds.
IIRC Julia's is a particularly simple method-based JIT for a dynamically-typed language.
I'm not sure exactly how it differs from most JavaScript JITs, but I believe it just compiles each method once for each set of function argument types - for example, it doesn't try to dynamically determine the types of local variables.
Diagram: https://docs.julialang.org/en/v1/devdocs/img/compiler_diagra...
Documentation: https://docs.julialang.org/en/v1/devdocs/eval/
From what I understand, Julia doesn’t do any tracing at all, it just compiles each function based on the types it receives. Obviously Python doesn’t have multiple dispatch, but that actually might make compilation easier. Swap out the LLVM step with python's IR and they could probably expect a pretty substantial performance improvement. That said I don’t know anything about compilers, I just use both Python and Julia.
reply