MacRuby recently started to implement their backend compilation on top
of LLVM, and it seems to be paying substantial dividends for
performance. On integer math benchmarks, they're several times faster
than JRuby. On closure-performance benchmarks, they're at least twice as
fast. Most of their performance boost seems to come from a couple
specific optimizations:
* True fixnums! I don't think we'll ever be able to compete on math
performance until we either get fixnums in the JVM or have enough
information to eliminate constructing them. My early attempts to do this
have involved adding some "long RHS" call paths, which certainly helps.
But we're still constructing too many fixnums, and nothing seems to get
around that fact. Even Java 7 escape analysis combined with my dyncall
inlining work has no effect.
* Something like alloca. MacRuby generally allocates runtime structures
with alloca, which appears to reduce their overhead substantially. In
our case, closures are allocated with normal heap-based objects, and we
pay the full cost for doing so. If we could reify local variables into a
heap structure lazily, or stand up a scoping structure that only lived
on the stack, we might get closer.
* Lack of an optimizing compiler framework for JVM. The truth is that
we're expecting too much of the JVM. We need a better compiler framework
that can do some type inference, constant propagation, etc, and be aware
of what bytecode and runtime logic optimizes well. The work Tobias is
starting on ssa-compiler will be important...we need to find a way to
move it along faster. I have a couple books and papers to read so I can
be useful in this regard.
I'd like to hear what other languages, especially dynamic languages, are
doing to take the next performance steps. I'd also like input on what we
can do to continue improving JRuby, and hopefully improve the state of
dynlangs on JVM at the same time.
- Charlie