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