On Tue, Oct 27, 2009 at 9:39 PM, Bill Kelly <billk / cts.com> wrote:
> It would certainly be the best of all possible worlds
> to have ruby code run two orders of magnitude faster
> without giving any hints to the compiler.
>
> In theory, then, should it truly be possible for the
> ruby compiler to generate code that keeps floating
> point values in registers, performs arithmetic on them,
> and then passes the resulting values off to other
> methods, without ever allocating the float objects on
> ruby's heap?
>
> (Or maybe such a thing would instead be achieved at
> run-time through JIT'ing and sophisticated hotspot
> analysis?)

Anything is possible. It's just really hard.

Even the best optimized dynamic language runtimes, many of which can
put values into registers and turn math into extremely fast low-level
native operations, still need to obey the semantics of the language.
In Ruby's case, that means you still need to ensure that the values
being passed into a numeric algorithm are actually Fixnums and make
sure that Fixnum itself has not been modified. If you don't check the
former, you may do optimized math against a non-math value. If you
don't do the former, Fixnum's mutability could lead to method
replacements (uncommon for math, admittedly) not being reflected in
already-optimized code. Performing those checks might be cheap, but
it's never free. In Duby, as in the JVM below it, if you're working
with a primitive int, you'll always be working with a primitive int.
Similar (but perhaps not as strong) guarantees apply to non-primitive
types.

> Some of the more impressive Smalltalk benchmarks I've
> been able to locate so far, still hedged a bit with
> the following caveats:
>
> http://www.cincomsmalltalk.com/userblogs/buck/blogView?showComments=true&entry=3354595110
>
> "One more note about the Integer Arithmetic benchmark.
> C# is smart enough to move memory variables to registers
> at the start of the method and then just perform the
> arithmetic in the registers. This isn't really typical
> behavior in a real system where the arithmetic operations
> are scattered throughout the system. In order to make it
> more fair, I made the variables into instance variables
> and marked them as volatile to force C# to fetch and
> write them all the time. This makes the comparison to
> Smalltalk much more fair."
>
> That seems a bit disingenuous to me. The advent of such
> in-register optimizations is what finally allowed us to
> stop using the 'register' keyword in C about 15 years ago.
> Now it's implied we can toss that all aside in order to be
> 'fair' to Smalltalk?
>
> I'm going to have to call shenanigans on that.

Shenanigans indeed! I've made the same sorts of claims myself, like
"JRuby is only a couple times slower than Java, /for equivalent
work/". That's my subtle way of saying "Java numeric algorithms that
work with all boxed 64-bit values and do virtual dispatches for all
math operations." It evens the playing field, but of course nobody
writing Java would write numeric algorithms performing virtual calls
against boxed 64-bit values. In my defense, however, math is one of
the few areas where JRuby will probably never be as fast as Java (or
Ruby implementations that don't need to use objects for Fixnums),
since our dynamic calls are almost as fast now as Java's virtual or
interface calls. If you're working with a bunch of non-numeric objects
in JRuby, we do very well.

> But anyway, if it's truly theoretically possible to achieve C-like speedsn
> ruby without giving any hints to
> the compiler then I'm all for it (obviously).

It's certainly possible to do much better than we have been doing.
MacRuby and Rubinius, for example, are now showing extremely good perf
numbers for numeric algorithms. In Rubinius's case, the recent JIT
work has started to make it conceivable that a pure-Ruby standard
library may be able to get within a few times of MRI's
implementations. And experiments with JRuby have been able to double
or triple our current Ruby performance, simply by making it easier for
the JVM to optimize Ruby code the same way it optimizes Java code. We
are able to approach both MacRuby and Rubinius even for numeric
algorithms where they have an advantage. It's an uphill battle--the
nature of Ruby is such that even our best efforts are littered with
performance-stealing typechecks--but we're all making great progress
and learning from each others' efforts.

Even if Ruby could run as fast as C (or Java, in my case) it would
still not fit the other requirements of Duby, like having no runtime
library or being able to present "real" Java classes and methods. So I
think even under the best circumstances, Duby (or something like it)
is still needed.

> Otherwise, the remarkably unobtrusive type hinting Charlie
> is experimenting with seems to me _vastly_ preferable to
> the current situation of having to drop into C to get the
> speed. I don't *like* static typing. But I like having
> to drop from Ruby into C even less.

Just as I find it ironic that I work all day, every day, implementing
Ruby...by writing in Java. It has led to a very solid, reasonably
performant implementation, but it would be a lot more fun to write in
something Ruby-like. If I can get much of what I like about Ruby by
using Duby and pay no performance penalty *at all*, I'd be very happy.
And you all might find it easier to contribute to JRuby, too :)

> I suppose the worry must be that there would be a slippery
> slope, where if such static type hints existed in Ruby,
> they would be overused, and we might end up with a
> proliferation of third party gems and libraries which were decidedly
> un-ruby-like.
>
> Perhaps it would be possible for the compiler to always
> generate two versions of any method which was declared with
> type hints: the static version, and a purely dynamic
> standard ruby version. Then such type-hinted methods would
> in effect provide an optional fast-path for users who were
> in need of maximum speed, without imposing any un-ruby-like
> restrictions on other users?
>
> If that were possible, would there be any downside? (An
> honest question. I'm not thinking of any myself, so far.)

Interesting that you suggest this. I am also going to add dynamic
dispatch to Duby.

A second language project of mine, Surinx, is essentially Ruby syntax,
Java/JVM types, but all *dynamic* calls. It requires the dynamic
dispatch support coming up in Java 7, and it has a small runtime
library, but otherwise it is also written entirely in Ruby.
Performance is rather interesting with Surinx; it's much faster than
JRuby, since it doesn't have to deal with a mutable type system and it
lets the JVM optimized dynamic calls. For "equivalent work", Surinx is
only about 50% slower than Java, and that gap is likely to narrow as
the Hotspot engineers improve dynamic call optimzations.

But there's no real reason to keep the languages separate, so I intend
to merge them. The new language will be statically typed, except where
types cannot be statically determined (or perhaps where you explicitly
declare them as dynamic). If you write with no static types at all,
there will be very little to distinguish the syntax from plain old
Ruby (though of course it's still *not* Ruby, because it's still based
on Java's type system and class libraries).

Dean Wampler suggested the name "Dubious", which seems to fit its
dubious nature extremely well.

Surinx and Duby codebases are on my github account.

- Charlie