Don't count on Ruby getting 10x faster anytime soon. The meta-object model and method-missing reliance of many of the libraries make performance optimizations of JITs a very limited enterprise.
While your work is very impressive, and I'm a big fan of Graal and systems like it, I think it's a mistake to say that something is solved when there's a single research system that gets good performance. As another example, there have been systems with fast continuations for 40 years, but I still wouldn't call that solved. I've built a JIT that's very effective at optimizing contracts, but I don't think that's solved either.
Well the statement was that it was not possible to remove the overhead of method_missing (well they didn't actually say 'impossible' but that's how I read it, and I also took them to be referring to peak performance, because people usually are).
I solved the problem of showing that it is possible to do that. Before people thought it was impossible, and now they know it isn't.
I'm not claiming I solved other problems such as removing the overhead with low memory or removing it in corner cases.
I hear the Truffle+Graal combination is getting very good results about Ruby. Here is video about it (pointed to the missing-method example): [1]
They're hitting 35x in some benchmarks [2]. Most benefits being in workloads where Ruby has to continuously talk to C; the result-passing part gets compiled away.
It is available in Java 9, if I'm not mistaken. LLVM IR bytecode ingestion is in preparations too [3].
Three of the biggest Rails Shop, ( this is assuming the most popular, resources heavy usage are Rails related. ) all run on CRuby. That is Cookpad, Shopify, and GitHub. ( Basecamp in rather small compared to these 3 )
I wonder if there are any popular webshop ran on JRuby, or why those three dont use JRuby.
It's true that many libraries would perform poorly because of a reliance on method_missing. But what can be made quite fast is code that either uses define_method instead, or uses define_method on the first failed call.
In fact, a tracing jit could even make the method_missing case fast by automatically specialising and optimizing missing coupled with a vtable/dispatch table.
My forever-in-progress ahead-of-time Ruby compiler uses vtable based dispatch for every method name that's seen in the program at least once, and that's usually most of them (unless people e.g. construct method names dynamically at runtime).
To handle method_missing, it creates thunks for each method name and fills the missing vtable slots with those, which is similar to what I suggest above - the next step of dynamically optimising method_missing for called symbols and replacing the vtable thunks would be a relatively minor step in a JIT.
I don't think anyone expects Ruby to get dramatically faster in the very short term, but there's lots of opportunity to make most Ruby code much faster in the medium term.
I think we'll also start seeing implementations that do things like JIT influence how people write Ruby, because a lot of things won't matter much for MRI performance but will be a huge deal for implementations that uses compilation techniques, so it's possible to get a lot more "compiler-friendly" Ruby while still writing clean Ruby that runs well on other implementations.
e.g. the above "define_method on method_missing" basically boils down to (pseudo code):
def method_missing sym, *args
raise suitable exception if sym doesn't meet right criteria
define_method(sym, args...) do
... whatever ..
end
send(sym,*args)
end
If it lets an implementation speed up its (ab)use of method_missing enough, you'll see people adopt stuff like that.
Smalltalk has those same features (which is where Ruby got them from). Almost all of the high performance JIT technology we use these days was originally invented by Smalltalk VM hackers. They invented that stuff specifically to make that kind of code go fast.
The 3x was compared to Ruby 2.0, on some slides they claim Ruby 2.4 is already 30 - 40% faster then 2.0, so effectively you will only get around 2x more speedup.
Java with Ruby's syntax and undeclared typing would make Java programs so shorter that it would be worth it. But there would be nothing left of Java, except the object orientation. It would just be a simpler more static Ruby.
No because it's statically typed, too much work programming like that and it's not worth it for the kind of software I develop (backend of web/mobile apps), but thanks. Suggestions are always appreciated.
It's object oriented and runs on the top of the Erlang VM. It maps classes on gen servers, which is pretty natural and it spares the developer all the boilerplate of creating a gen server module. Unfortunately the language designer killed it because "it's pretty bad to have two competing niche languages with nearly identical features." The other language was Elixir. However the two languages are very different. Elixir is 100% functional, Reia could have been the language to transition millions of OO developers to a functional and concurrent world. I could have used it instead of Ruby.
This is an odd stance. Backends are where static typing shine, and where those who like static typing sing its praises. Maybe you just don't like static typing?
I really don't find static typing to be more "work". You still have to think about types in dynamically typed languages, you just get to skip specifying them.
Skipping that saves a lot of keypresses and time. I always found very little help from static typing. I know what I'm doing if I type hash = {} in Ruby and there is no need to declare it as HashTable (what else could it possibly be?). About the types of the keys and values, they don't matter much in my experience. Maybe it's Ruby or it's Rails, but they tend to fall right into place without surprises.
In case you're not aware, many static languages have implicit typing nowadays. I still write Ruby most often, but for example in Go you could just write `something := "string"` and with that := operator it'll manage the type assignment for you. Lots of other static languages offer that now also. I'm not well versed on modern Java, but the type system in Go pretty much gets out of the way for the things I've done with it.
> I type hash = {} in Ruby and there is no need to declare it as HashTable (what else could it possibly be?)
In java you have options other than a HashMap, there is LinkedHashMap (which preserves insertion order) and TreeMap (which stays sorted according to a comparator). There are also extensions for things like Immutability. The checking can also guarantee that it will only have one type of object, or a common interface, or you could allow it to accept any kind of object.
So, yeah, there's quite a few things that an associative array could be, and there's reasons for all that, and i've used most of these on web backends.
There are other ways of meta programming that are still performant.... that is why many Ruby devs see Elixir/beam and Clojure/jvm as good language/platform alternatives.
If you don't mind starting from scratch and using a statically typed language, crystal is amazing. However, you will not get vary far porting any large ruby project to crystal without a rewrite from scratch.
However many of the libraries list under "third party" are either unmaintained or not really ready for production. The stuff in the standard library seems pretty good though (although I've not used Nim for serious production work)
Except it's nothing like that, it's like an interpreter framework written in Python with a reference implementation that happens to be a Python interpreter. Write your interpreter in RPython, use the right decorators and boom you have a compiled interpreter with a free JIT (with speeds that beat C in some workloads, apparently).
This is an improvement to standard MRI Ruby, also called CRuby. This is an experimental JIT compiler which probably won't get adopted into mainline Ruby, but will definitely cross-pollinate with it. A JIT compiler has been a goal in MRI development for a long time. Nobody is likely to adopt this for anything, it would take more work to get this working with the current installed base of Ruby code than it would be to just rip ideas from it and put them into Ruby 3. It's just cool as a proof of concept.
Other Ruby implementations suffer from not being compatible with the MRI ecosystem, you have to port them over. In theory because they're the same language, gems would be easily portable, but the sheer amount of combinatorial work involved means they slowly accrete into separate ecosystems. It's relatively easy to port a gem over and maintain it, but if you don't keep doing it, they'll become incompatible.
MRI has the largest install base, and the biggest gem library, and the largest number of eyes on it. Sure, JRuby and Rubinius are faster, but Ruby was never a language chosen for speed, so most devs reach for MRI first and then only branch out when requirements force them out.
For me, the differences between MRI and other implementations effectively make them different languages, I'd jump to Elixir before giving JRuby a shot. I have a sense that other Rubies, except maybe Opal, will always be niche.
The Ruby community is always likely to prefer MRI because that's the core that the majority of gems support.
So, yes, on the surface of it, this particular Ruby build might appeal to people looking for performance.
But from a language research position it is interesting to decouple concepts like GC from the language so that they can be studied and optimized as a pattern and then be potentially reapplied to any language runtime.
I agree that some concepts might be pulled into MRI Ruby 3, but OMR may be a powerful testbed for language researchers to debate GC strategies and measure effects in various languages before committing to a single language integration.
Thanks! That's definitely the exact hope we have for OMR as well.
Similarly, improvements in OMR can be shared among all languages using it; ie, because we build both IBM's Java JDK and Ruby on top of OMR, Ruby can benefit from investment in Java, and Java can benefit from improvements in the Ruby community.
> The Ruby community is always likely to prefer MRI because that's the core that the majority of gems support.
It may be worth rembering that today's (1.9 and later) "MRI" started life as an alternative to MRI called "YARV". For a while there was a lot of talk about Rubinius as potentially being the basis of a similar replacement and becoming the "MRI" of the future. While there is less talk recently about Rubinius in that role, its absolutely not impossible that a competing core engine could be adopted as the mainline implementation of Ruby again.
1. It is mostly compatible with Gems.
2. It is faster and accepted by the Core Team.
3. Most importantly, license. Both MRI and YARV, the two CRuby implmentation are all MIT. It is highly unlikely JRuby or OMR could be used as mainline.
Interesting, For many years I was all in on MRI and down on JRuby but over recent years I've been quite happy with JRuby for certain things.
The reality of JRuby startup times make it not a good fit for scripting tasks but otherwise server and threaded tasks are a great fit. Since using JRuby more recently I feel the ecosystem support is probably the best of the non-MRIs. I rarely run into compatibility issues. Conversely JRuby's Java integration has been a very useful feature that no other Ruby implementation offers.
> or me, the differences between MRI and other implementations effectively make them different languages, I'd jump to Elixir before giving JRuby a shot
Wha? Sorry but this sounds pretty FUDdish. I have never had an issue with JRuby to the extent that you are describing. Do you have some examples?
I know of many large app deployments in JRuby at large household name companies.
The only thing JRuby doesnt have is the relatively niche CExt functions.
I use jruby on my hobby projects at time (GUI support is great!) however...the startup time is...always...so...awful...it is truly painful. I'm basically moving on to either crystal or go now, it just wasn't worth it anymore.
As somebody not into the whole ruby-ecosystems: What's an example that breaks compatibility between ruby and other implementations? And what's so wrong with JRuby that you won't even consider it?
I have considered it deeply. Many of our enterprise systems are Java-based, so JRuby's ability to call Java methods directly without implanting services would be a huge pragmatic boon. But every time I consider that I have to balance it against being able to use a constellation of gems in Rails. For example, nokogiri (libxml) is used in a ton of stuff. Sure there are Java equivalents, but that isn't the issue. Rather I would have to reimplement or find replacements for everything we use that depends on that without introducing side-effects. In my experience that's really hard unless it's a toy application without many dependencies. (Read: opposite of most enterprise Ruby apps)
Also, as a gem author I've tried to support jruby along with MRI, but it requires jumping through a lot more hoops. Of course any cross-platform code requires more work to support, but it's a pressure on small devs. If no one needs it, no one helps support it, so then it becomes another gem that is effectively MRI-only. Kind of a viscous cycle.
Rubygems forms an ecosystem of libraries on top of Ruby. Most gems are dev/tested within MRI, some work across other Rubies, some do not. It's difficult to tell which is which. This means most teams choose MRI in much the same way that most Ruby teams choose some form of unix -- compatibility.
Ruby also suffers from the lack of a formal VM, so other implementations are merely similar rather than being guaranteed to run all programs. This is not the same with JVM vendors, where choice of IBM vs Oracle is largely based on extrinsic features rather than intrinsic compatibility. (Or at least you have to get in really deep to find differences-- in Rails you usually find incompatibilities that stop you from even starting the app).
A different driver to the database for MRI and JRuby. Not a big deal.
The deal breaker for me is the very slow startup time for tests and no gains for run once scripts. I've seen people developing with MRI and doing CI on JRuby to work around that. It's worth doing that only if you have a service running with some real load. Most internal services do nothing almost all the time.
Once that's stable, then I'd like to focus on trying to some of this code integrated into MRI upstream, perhaps as an experimental branch for the 2.5 development cycle, or as something that can be compiled in optionally.
In parallel, I'd like to work on improving performance . We've not put a lot of effort into performance, and have instead focused on compatibility and currency, so that we have a good base from which to grow performance on top of.
Related, are you aware of the JRuby+Truffle project [1]? Not a new high performance JVM language, but a high-performance implementation of Ruby using Truffle and Graal. On the surface it sounds extremely similar to Ruby+OMR (applying a high-performance, production-pedigree compiler/interpreter to an experimental Ruby implementation), so I'd be interested in hearing about any direct comparisons or knowledge-sharing between the two projects that might be possible.
I really enjoy meeting up with the JRuby+Truffle people whenever I can at conferences. Though our approaches are really different, there's definitely a cross-pollination of ideas: I've taken huge amounts of inspiration about what could be possible from Chris Seaton's PhD work which was on JRuby+Truffle.
Officially, OMR is a meaningless title, like LLVM. Similar to LLVM, it once stood for something, but then we realized that it didn't actually match the project's 'charter' quite as well as we had hoped... but had grown fond of the name (also... finding new names is super hard).
Original definition was 'Open Managed Runtimes', but we can do more than just managed runtimes with OMR technology, and so that seemed to sell it short.
Is the Open really open, as in acceptable license that won't hold it back from gaining adoption in OSS and Enterprise community - or - are there licensing, patents or other proprietary strings attached?
If Ruby can get faster than Python sooner, I'd switch focus to Ruby (and somewhat make Go less of a priority for us).