Sunday, November 23, 2008

Noise Cancelling

Short thoughts on KirinDave's post The Opposite of Momentum, which the anti-Ruby crowd has latched on to as more evidence that Ruby is "falling flat on its face".

Dave's post appears to largely lament the lack of progress in the C implementations, be it their lack of performance, presence of memory leaks, or relatively primitive GC implementations. He briefly mentions alternative implementations, calling Rubinius "the light and hope of the Rubyverse" and summarizing JRuby as "great" before dismissing both.

In Rubinius's case, he may have a point. There have been many setbacks, and after a year of funding six developers it's still not really usable for real apps. The sad news that their team has been cut to two paid developers certainly doesn't help. Most will agree that the Rubinius ideal, that of Ruby implemented in Ruby, is a great goal...perhaps the highest ideal for a Ruby implementation. But in practice, it's turned out to be a lot harder to execute...and impossible to execute in a year with six smart hackers.

Update: My intent here seems to have been missed. I am not in any way claiming "Rubinius sucks", because Rubinius isn't even finished yet. I would not make such a claim about any incomplete project. I mention Rubinius only because Dave dismissed both in the same breath; to address one case I felt I needed to address the other. Rubinius will succeed...of that I have no doubt. And already it has proven many things possible nobody ever expected to see. It's unknown how long it will take to "get there" but it will "get there" eventually, and be a major contender for replacing the standard impls. Dave's use of Rubinius to help prove a lack of momentum is almost as questionable as his out-of-hand dismissal of JRuby. We've started to attempt an integration of Rubinius's kernel into JRuby, and we've added Rubinius's FFI and MVM APIs because they were very well-designed. We continue to contribute to the RubySpecs, and I eagerly offer any technical help I can whenever the Rubinius team has questions about how JRuby solves certain problems. What more good things do you want me to say about Rubinius?

However when we look at JRuby, Dave is entirely wrong to dismiss it in a single sentence. JRuby *is* what he wants, in almost every way.

  • JRuby runs on the best available dynamic language VM, Hotspot. Hotspot has its roots in the Smalltalk world Rubyists hold in such high esteem, and real steps are being taken to make it even better than before for dynamic languages. The end result will be trivially inlinable dynamic calls nearly as fast as static Java code, which no other VM in the world can claim.
  • JRuby does not have GC headaches and memory leaks like the C impls because we use the existing GC options on Hotspot...which are, again, some of the best GC implementations in the world. It's folly to say that an implementation from scratch is going to be able to compete with JRuby on JVM, because the simple truth is that making a world-class VM and/or GC is super dooper hard.
  • Even where JRuby still stumbles a bit, like the classic JVM problem areas of memory use and startup time, we've made huge strides. JRuby starts up no slower than Rubinius at its fastest...in many cases under a second. And memory-wise, we pay little cost beyond the JVM's own 20-30MB memory tax, while still working to reduce our overall consumption with every release.
  • JRuby is also moving faster than any implementation available. A year ago, we were generally a bit slower than Ruby 1.8.6; this year, we're faster in most cases than Ruby 1.9. A year ago, there were a handful of early-adopting production users; this year, dozens of them, ranging from small orgs and agile projects to governments, banks, and telecom. There's no lack of momentum when it comes to JRuby.
  • To top all this off, there's still dozens of folks working to make Hotspot even faster, it's GCs even smarter, and we just come along for the ride. Yes, we've done a lot because we haven't implemented our own VM specifically for Ruby. But that's exactly the point...we've been able to focus on areas that matter most, like actually running apps and running them as fast as possible.

The bottom line, as far as I can see it, is that if the C impls of aren't moving fast enough, and the "light of the Rubyverse" is hitting a few roadblocks, you damn well better give JRuby more consideration than one sentence. I certainly hope this wasn't a reflection of any continuing anti-Java bigotry in the Ruby world, since as I've mentioned previously that attitude will only make things worse. If it reflects simple ignorance as to why JRuby really will be a better Ruby, then we're not doing a good enough job educating...help us do better.

JRuby is continuing to do things no other Ruby has been able to do. We've cracked the Enterprise glass ceiling, with numerous deployments inside some of the most rigidly Java-centric and intransigent organizations around. We've shown it's possible for Ruby to perform extremely well, and we've only scratched the surface of Hotspot's potential. We've implemented most of Ruby 1.9's features in just a few months, where other implementations have barely gotten 1.8 working. And we're just getting started...we have plans upon plans to continue improving compatibility, performance, scaling, and ease-of-use, and the various folks working on the JVM will continue making it a better and better host for dynamic languages. If you haven't used JRuby yet, you're really missing out. It's time to give it a try.

(Footnote: Don't take this as a shot at any of the other impls; it's obvious JRuby had a big head start, and we've been funded longer (albeit less) than most of them. This post is squarely focused on anyone like Dave that thinks if the C impls don't solve all Ruby's implementation woes, Ruby is doomed. The truth is that Ruby will survive despite any lingering issues in the C impls, and JRuby is a crucial part of that survival.)

20 comments:

  1. "Rubinius's case, he may have a point. [..]after a year of funding six developers it's still not really usable for real apps."

    Yeah: doing infrastructure work is always a thankless job. You seem to forget what's come out of all this:
    - RubySpec, the massive amount of executable specs that are now run by every Ruby implementation; this didn't exist before Rubinius.
    - ruby_parser (finally a Ruby based Ruby parser, something beneficial for _every_ Ruby implementation, and a first step to wean IDEs off the JRuby AST dependency)
    - ffi (which JRuby seems to be happy to adopt, but it originated in Rubinius)
    - the initial MVM implementation;
    - Rubinius Kernel and all the bits that'll allow to make Ruby go full turtle-on-turtle at some point;

    And I'm sure I'm forgetting a few other things. So yeah, it took longer to get up to speed than expected, but in the process the Rubinius gang improved the Ruby and Ruby VM space significantly.


    A last Nitpick: "Hotspot has its roots in the Smalltalk world":
    Who gives a plonk? The thing was forked off the Strongtalk source, what, 10 years ago. All the dynamic goodness has been covered by a thick Java/JVM crust... and now it'll take a few years to knock holes in that to get back at the fancyness that made Strongtalk fast. If it's "the best available dynamic language VM"s, why is it fighting dynamic languages all the way? (no lightweight classes, no lightweight methods, Permgen/classloader blowups, etc). I can definitely appreciate the technical and pragmatic benefits of Hotspot (stable codegen backend, wealth of stable GCs,...), but that kind of hyperbole is best left to marketing bunnies.

    ReplyDelete
  2. I have used JRuby for a bit between 1.0 and 1.1.2 (I think) and it worked great for the most part. With the continuing improvements I imagine it is a great alternative to MRI.

    Howhever, the biggest JRuby limitation and the one stopping me from using it fully is the support for most C-based gems. If I want to use NArray ou Ruby GSL I'm stuck with MRI.

    Do you plan to solve this, somehow? I know FFI is a good mid/longterm solution but it doesn't cover all cases, especially if it isn't used by gem developers.

    Cheers. Keep up the great work!

    ReplyDelete
  3. Murphee: Thanks for stopping by! WRT Rubinius you are correct on every point, except that JRuby was the first impl with MVM and the recent JRuby team work was to make good on bringing FFI to MRI. I explicitly called out Evan for coming up with the original API, and noted we and the Rubinius team worked together to improve that API. But you missed my point entirely. If Dave's purpose was to point out that C ruby users aren't a great deal better off running real apps on real, working implementations, Rubinius does not represent any sort of answer to that accusation. Many great things have come out of Rubinius, there's no denying it. But Rubinius itself is not yet a compelling answer to the "ruby implementations suck" claim. I've no doubt it will be some day.

    WRT Hotspot, I'm not sure you have all the facts, or else you are unintentionally misrepresenting them. Hotspot is far more than a nice codegen backend and a handful of GCs. No other mainstream VM can inline across dynamically bound calls. No other can optimize those calls as a whole. No other can dynamically promote objects from the heap to the stack if they do not escape a compilation unit. And perhaps most importantly, no other can do all this aggressively, eagerly, knowing that its deopt capabilities will fire if early assumptions prove false. It is perhaps one of the least-appreciated pieces of software in the world, and belittling its potential simply because its Java exterior is most apparent is myopic at best. Yes, that exterior makes it a bit trickier to implement dynamic languages, but no more difficult than its nearest competitor, the CLR (with or without the DLR). And improvments are being made and will ship in Java 7...as if that were necessary, since Hotspot is OSS and buildable by anyone anyway. It is a far, far bigger deal than you give it credit for, and your do a disservice to your readers by saying such things.

    ReplyDelete
  4. "But Rubinius itself is not yet a compelling answer to the "ruby implementations suck" claim."

    You *can* make a broader point concerning the Ruby community without taking potshots at Rubinius, can't you? I say this as an outsider; I don't program Ruby very often and my opinion may not be worth very much. But I follow JRuby somewhat loosely and I find that kind of behavior somewhat disconcerting.

    It very much comes off as "Rubinius sucks. Oh, I don't really mean that; its developers have done so much good. But did I mention how much it sucks?"

    ReplyDelete
  5. james: I appreciate that my tone did not appropriately convey my intent. I do tend to be a bit clinical in my assessment of competing implementations. I've added a short update to help clear things up.

    ReplyDelete
  6. tonio: Wayne Meissner of the JRuby team made an attempt at supporting C extensions, and while he was able to get basic ones working, we decided very quickly that it was not going to be worth the effort. C extensions are not always simple nice-to-have add-ons, they are frequently also invasive memory-twiddlers inextricably married to C ruby's internal implementation. To support them in a general way means mimicing the internal APIs of String, Array, Hash, and others in such a way that they are indistinguishable from C ruby itself. In some cases, it's possible, albeit with horrendous performance overhead from copying data back and forth (to/from JVM heap to pinned memory the extension can use). In other cases, it's nearly impossible (many extensions depend on C ruby's specific implementation of Hash, which we can neither mimic nor reasonably marshal back and forth).

    Ultimately, however, FFI is the only way Ruby itself is going to be able to grow beyond the current C impls. Because current extensions have full, unfettered access to the internal structure of Ruby objects, the optimization and redesign potential for C ruby is very limited. A new GC can't simply be dropped in, since extensions have access to live memory addresses. The memory model can't be changed substantially. Optimizations to object internals can't be implemented. C extensions are at once a great boon to the C impls and a great curse. Argue vigorously for their abandonment, and when using JRuby help implement or seek out alternatives that may already exist.

    ReplyDelete
  7. This reminds me slightly of the GNU/Linux relationship that has evolved. Linux users say "Linux rocks!" Stallman points out that Linux is built on GNU tools, which were developed while putting down the basis for a kernel (IIRC). I know it's not an exact comparison, but it's what I was reminded of. :)

    ReplyDelete
  8. Charles:
    I have been following JRuby's progress with great admiration, and using JRuby for small personal projects. (Still write Java for pay). JRuby is currently IMHO, the best Ruby implementation happening.
    My question is, is there a way to bundle up JRuby with a minimal JVM, or does JRuby inevitably come with the entire 72 MB (and growing) JVM?
    I know, we live in a world of cheap 8 GB flash drives, terabyte hard drives, and 4 GB of RAM so maybe I should just get over wanting something that feels tighter and smaller than JRuby with all of Java. I get the entire boatload whether or not I need it or use many portions of it in my application. Any thoughts?

    ReplyDelete
  9. What annoyed me a lot was that the guy you mentioned (the one who was bitching against ruby losing momentum) - does not even have a comment field.

    Blogs/Writeups without comment fields are a complete waste of time - and incredibly boring.

    So, heads up for you!

    ReplyDelete
  10. I read that guys whining post earlier in the day. I thought a lot of his concerns were answered by JRuby, which he obviously hasn't tried at all.

    I also don't get why he dismissed 1.9, which I think is an important next-step for ruby.

    Anyway - he's way off base...

    ReplyDelete
  11. > If it reflects simple ignorance as to why JRuby really will be a better Ruby, then we're not doing a good enough job educating...help us do better.

    I was really encouraged by what I saw at the JRuby talk at RubyConf.

    Previously you've focused on things like, "hey look, you have access to all these awesome Java libs" and "you can deploy WAR files". But your average Ruby dev sees those Java libs as just a set of really ugly APIs, and as for war files, I think the response is something along the lines, "We are a peaceful people..."

    But this last talk I heard you focus a lot more on stuff that Rubyists care about. Memory savings, good I/O, easy deployment... these things speak a lot more loudly to us.

    ReplyDelete
  12. @Anonymous: Why being Anonymous ? ;-)

    @JRuby team: Keep the hard work, what you are doing with JRuby is great for Ruby AND great for the JVM too !!!

    ReplyDelete
  13. Charles & Team,

    You've done an amazing job with JRuby. It seems like only yesterday when JRuby was too slow even be usable. You've come so far. I agree that the only rational road forward is Ruby on JVM and hopefully CLR someday. However, it sounds like the 37 Signals team isn't using JRuby and I can't understand why they wouldn't unless it's conservatism/legacy issues. I'd love to hear their answer.

    ReplyDelete
  14. Jruby runs faster than 1.8.x MRI in nearly all benchmarks... Apart from when running Rails. When will this change?

    ReplyDelete
  15. Well said. Java is a great platform for "dark corner" server-side in-a-rack deployments and after evaluating JRuby for a while we're ready to move on in that direction. Very impressive indeed.

    The original rant, however, is still valid. JRuby, while great on a server side, will never become a mainstream implementation precisely for the same reason Java was never able to, and you mentioned them yourself: minimum 30MB of JVM plus the startup delay, while MRI is 3MB and it starts under 100 milliseconds on my MBP.

    When MRI gets to CPython level of maturity I'll see no reason not to develop general purpose software in it, reserving JRuby for high-performance, high-volume server work.

    ReplyDelete
  16. First of all, the bug in Tom Werner's logger that KirinDave mentioned has been solved in Ruby 1.9.x. Together with many other problems.

    The language and culture barrier may make it hard to see that our friends in in Japan are working hard on making MRI better. MRI 1.9.x is a huge improvement over MRI 1.8.x. For me, in the game I'm programing, it has proven to be between twice to ten times as fast, and it has a better memory use, better stability, less problems with garbage collection, and some nice extra features that round off the language and make it even more fun to use.

    I think that with MRI 1.9.x, Ruby is as stable CPython as is technically feasible, seen the different way they handle memory. And with JRuby, it's more so, and a lot more secure to boot.

    KirinDave seems to want more features in Ruby, but which one? If you think Ruby if moving forward too slowly, or if you want new features, then please help implementing them in stead of complaining. Matz himself knows well that Ruby needs more momentum, but he can't make it alone.

    Finally, JRuby has an underestimated great potential: ever heard of the gjc, the Gnu Java compiler? Between JRuby's ability to compile Ruby to java bytecode, and gjc's ability to compile Java bytecode to native code, we're close to getting a Ruby-to-native compiler.

    ReplyDelete
  17. Just to be picky:

    "No other mainstream VM can inline across dynamically bound calls." - I think you forgot other first-grade JVMs like IBM's and BEA^H^H^HOracle's, they both do aggresive devirtualization etc. (although the last time I checked, HotSpot was still the best on this). But this raises the interesting question, how well does JRuby run on top of these other JVMs? Some of these guys are also moving into the dynamic language bandwagon, e.g. check IBM's new WebSphere sMash (Groovy & PHP), if their JDK is not good at dynamic languages I'm sure they should be working on this now.

    "No other can dynamically promote objects from the heap to the stack if they do not escape a compilation unit." - HotSpot doesn't do that yet (up to 6u10 or 6u6p). AFAIK this is now promised for Java SE 7.

    ReplyDelete
  18. Headius,
    JRuby is something you work hard for and result speak for itself. It should be something you and the world should be proud of and hence I do not see why there are some developers here that express discomfort over your tone.
    I do not see your tone as been arrogant becaue it is just your personality as you always speak and write in this tone.
    No amount of words can describe you and your mate's contribution and achievement to the Ruby's world.
    Do retain your individuality and personality because that is what make you a interesting genius.

    Your sense of pride and "showmanship" are something seriously lacking in many developers'blog because they are over-conscious of offending the reader that they suppress their joy and pride. Little did they realize that joy, pride and ego may be factors that drive them to their goals. And hence by suppressing those innate "tone", they are missing a good part of been a great developer.

    Keep it up !

    ReplyDelete
  19. I like Jruby. I might start to prefer it over MRI, simply because of the stable GC [though I'll admit some attempts have been made to help MRI currently]. That being said, could you please direct me toward benchmarks showing that jruby is faster "in most cases" than 1.9? [re: cagiano's benchmarks, alioth shootout, etc.] Let's be honest with ourselves here...
    Thanks!
    -=R

    ReplyDelete
  20. Charles I love JRuby! Used it on Netbeans and it was great. Fast and everything works. I love the fact that I can call Java from ruby. Excellent excellent work. I initially doubted your project would work. You have shown everybody that your choice was the wisest.

    One tip though, you have got to be a bit careful about how you come across. You tend to rub people the wrong way. Your a bit competitive so you have a tendency to run down other implementations. You will go a lot farther if you are careful about things like this.

    ReplyDelete