
Ruby 2.6.0-preview2 released with JIT - 15DCFA8F
https://www.ruby-lang.org/en/news/2018/05/31/ruby-2-6-0-preview2-released/
======
pjungwir
Congratulations Ruby team! I'm excited to hear about the performance
improvements. It seems like JIT could be a huge win since calling a method
requires checking all kinds of possibilities that are almost always not used,
but might be. I would love to keep all the power & fun of Ruby without
worrying so much about performance.

Speaking of optimizing method calls: now that it's been a few years, I wonder
what Ruby folks think about refinements. Are you using them? Are they helpful?
Horrible?

I remember reading from the JRuby folks that refinements would make Ruby
method calls slower---and not just refined calls, but _all_ method calls [1],
although it sounds like that changed some before they were released [2]. It
seems like people stopped talking about this after they came out, so I'm
wondering if refinements are still a challenge when optimizing Ruby? I guess
MRI JIT will face the same challenges as the Java implementation?

[1] [http://blog.headius.com/2012/11/refining-
ruby.html](http://blog.headius.com/2012/11/refining-ruby.html)

[2]
[https://github.com/jruby/jruby/issues/1062](https://github.com/jruby/jruby/issues/1062)

~~~
transfire
As the creator of Ruby Facets, refinements were high on the todo list.
Unfortunately the syntax of refinements led to an ugly problem... I would have
to support two identical code bases to support both usages (monkey patching
and refinement), the only difference being boilerplate code. I could find no
way around it. That seemed ludicrous to me, and so I never bothered to add
refinement support. Hence, from my perspective, refinements went over like a
led balloon.

~~~
wasd
I've never heard of Ruby Facets but it looks interesting. Just as a heads up,
the api document links on
[http://rubyworks.github.io/facets/learn.html](http://rubyworks.github.io/facets/learn.html)
don't work.

------
hirundo
> Add a new alias then to Kernel#yield_self. [Feature #14594]

It might seem strange that they lead with this new feature, but `yield_self`
can greatly improve the Ruby chainsaw, and `then` makes it more accessible.

The style of writing a Ruby method as series of chained statements has a non-
trivial effect on readability and conciseness. `then` lets you stick an
arbitrary function anywhere in the chain. They become more flexible and
composable, with less need to interrupt them with intermediate variables that
break the flow.

I've been using `ergo` from Ruby Facets for years ... largely the same thing
... and the more I used it the more readable I find my old code now. Funny how
adding one very simple method can have more effect than so many other complex,
high effort changes.

~~~
atombender
Good article about yield_self:
[https://zverok.github.io/blog/2018-01-24-yield_self.html](https://zverok.github.io/blog/2018-01-24-yield_self.html)

------
sho
> We’re going to implement method iniling in JIT compiler, which is expected
> to increase Ruby’s performance in order of magnitude

An order of magnitude as in .. 10x? This seems too good to be true. Half the
arguments against Rails melt away like butter if that's truly the case.

Anyone with a better understanding of the details care to comment on the
likelihood of these performance gains being actually realised, and if not,
what we might realistically expect?

~~~
jashmatthews
Sinatra + Sequel is already very competitive in web performance with Go +
Gin[1]. It's the Rails convenience stuff which slows things down massively.
MJIT could probably bring Rails in line with Sinatra though.

Between Ruby 1.8 and 2.5, performance has improved around 13x in tight
loops[2]. The Rails performance issue has been massively overblown since 1.9
was released.

Ruby 1.8 was a tree walking interpreter, so the move to a bytecode VM in 1.9
was a huge leap in performance. Twitter bailed to the JVM before moving to
1.9. A lot of those 10-100x performance differences to the JVM are gone thanks
to the bytecode VM and generational GC.

Bytecode VMs all have the same fundamental problem of instruction dispatch
overhead, they're basically executing different C functions depending on
input.

Doing _anything_ to reduce this improves performance dramatically, even just
spitting out the instruction source code into a giant C function, compiling
it, and calling that in place of the original method. Another 10x improvement
on tight loops should not be a problem.

[1]
[https://www.techempower.com/benchmarks/#section=data-r15&hw=...](https://www.techempower.com/benchmarks/#section=data-r15&hw=ph&test=fortune&l=hr9kov&f=zik073-zik0zj-
zik0zj-zijzen-zik0zj-zijunz-zik0zj-cn3)

[2]
[https://github.com/mame/optcarrot/blob/master/doc/benchmark....](https://github.com/mame/optcarrot/blob/master/doc/benchmark.md)

~~~
meesterdude
I would have never thought a ruby stack would come anywhere close to Go
performance. The path to optimization used to mean abstracting the really
crazy parts into a Go microservice for things that just needed absurd
responsivity; but it's clear now that a slim ruby stack could also be very
effective - and without needing to learn a new language. Worthwhile to at
least explore before going Go.

Nor did i know that twitter jumped out of rails before ruby got performant.
Which means the argument that twitter outgrew rails isn't so correct anymore.

still, thanks for this insightful comment.

~~~
ksec
>Nor did i know that twitter jumped out of rails before ruby got performant.
Which means the argument that twitter outgrew rails isn't so correct anymore.

Twitter, even back in those days would have still outgrown today's Rails. It
was Ruby that has gotten a lot faster. Not necessarily Rails.

~~~
jashmatthews
From what I understand, the biggest issue was their product required fast fan
out messaging. Tumblr, for example, is still huge but can get away with 1000
lines of PHP for their feed:
[https://news.ycombinator.com/item?id=17154403](https://news.ycombinator.com/item?id=17154403)

------
virtualwhys
@darkdimius[0], the person who tweeted the referenced tweet in the article,
was arguably the primary contributor to Dotty[1] behind Martin Odersky (Dotty
will be Scala 3, the next major version of the language).

Once he finished his doctorate at the EPFL, off to Stripe he went, bye bye
Scala. Tough industry, on the one hand Scala benefits from a revolving door of
high level EPFL doctoral students, and on the other the talent pool shifts
around as students come and go.

Money talks, companies like Stripe have a leg up in that they can fund full-
time engineers to work on projects, whereas institution backed projects
typically have a much smaller pool of long-term engineers to rely on
(JetBrains, for example, has something like 40 full-time engineers working on
Kotlin/KotlinJS/Kotlin Native).

[0] [https://github.com/DarkDimius](https://github.com/DarkDimius) [1]
[https://github.com/lampepfl/dotty](https://github.com/lampepfl/dotty)

------
alberth
What’s the current sentiment as for what will ultimately lead to the best
performance of executing Ruby?

From my uneducated perspective, seems like Graal VM could become the de facto
Ruby deployment stack.

[https://github.com/oracle/truffleruby](https://github.com/oracle/truffleruby)

~~~
onli
I doubt that there are that many people that would allow Oracle tech to enter
into a beloved language like Ruby, or the ecosystem.

~~~
alberth
Why not?

Graal is EPL, GPLv2, LGPL licensed.

[https://news.ycombinator.com/item?id=16862130](https://news.ycombinator.com/item?id=16862130)

~~~
onli
Because Oracle is Oracle, the most evil company in tech, the one most
blatantly greedy. Look at what they pulled with Google. Oracle would wait till
the tech usage grows and then use patents and API copyrights or whatever else
they invent out of thin air to go after the players using its tech. The free
license of Graal does not protect you from that, GPL2 specifically not. See
[https://www.gnu.org/licenses/rms-why-
gplv3.en.html](https://www.gnu.org/licenses/rms-why-gplv3.en.html).

~~~
pjmlp
Google abused Sun, took advantage that they were in a critical financial
situation not able to sue, and when they crashed, did not move a finger to
rescue the company assets.

Now Android has Google's own J++, limiting what kind of Java libraries are
portable to the platform.

At the same time, some OEMs are adopting Android instead of Embedded Java,
thus increasing the fragmentation about what Java libraries are actually
portable.

Google just though they could let Sun close doors and get away with how they
created their own J++.

~~~
onli
That's Oracle propaganda. Sun was perfectly happy with Google using Java and
the free entry into the mobile market they got from that. See
[https://www.zdnet.com/article/a-google-android-and-java-
hist...](https://www.zdnet.com/article/a-google-android-and-java-history-
lesson/), [https://www.zdnet.com/article/sun-ceo-explicitly-endorsed-
ja...](https://www.zdnet.com/article/sun-ceo-explicitly-endorsed-javas-use-in-
android-what-do-you-say-now-oracle/).

~~~
pjmlp
That is Google propaganda.

Sun did what they could to save their face.

"Triangulation 245: James Gosling"

[https://www.youtube.com/watch?v=ZYw3X4RZv6Y&feature=youtu.be...](https://www.youtube.com/watch?v=ZYw3X4RZv6Y&feature=youtu.be&t=57m42s)

Also doesn't change the fact that even with Android 8.1, I as Java developer
cannot take a random jar from Maven Central and be certain it won't crash and
burn on Android, regardless of the version.

~~~
onli
Good link.

But I don't see how you can tolerate that contradiction. Either you agree with
Oracle that the Java APIs were copyrighted and Google should not have been
allowed to reconstruct them. Or you worry about fragmentation coming from an
incompatible Java implementation. Doing both is nonsensical.

~~~
pjmlp
What contradiction?

Google should have paid Sun instead of playing a Microsoft's move fostering
Sun's downfall, period.

And in doing so, Android would have been JavaSE compliant plus whatever
additional libraries they would think to drop on top of it.

~~~
onli
How do you come to the idea that having more Java devices available, even if
not 100% compatible, would have in any way caused harm to Sun? And then even
that much that it killed the company?

On top of that, I don't see for what google would have had an obligation to
pay.

Contradiction: Google broke some imaginary copyright by re-implementing APIs,
but Google is bad because the re-implementation was not 100% equal to the
original causing fragmentation. Either the fragmentation was harmful, then the
API copyright was the problem. Or the API copyright violation was the problem,
then fragmentation was the explicit goal and Google's try to minimize it the
problem. Both can't be true at the same time outside lawyer lala land.

~~~
pjmlp
Because those devices run Android Java, which Sun saw $0, thus not able to
capitalize on it to pay their bills.

1 - Google did not pay for Java licenses, when it should. Even Andy Rubin
admits that on his emails.

2 - To this day Android is not Java SE compliant, thus creating a
fragmentation between Android Java and Java. Just like Sun managed to prevent
with J++

3 - Being a Java license as Google avoided to be, and still isn't (many Java
APIs are not yet available on Android), would have required Android to be
fully Java SE compliant

So to conclude, Google tricked Sun and fragmented the Java eco-system.

They should pay and provide a 100% Java SE compliant implementation, or be
honest about it and fully migrate to Kotlin, Dart or whatever they feel like
it.

------
wwarner
A standardized AST! That's a big win.

~~~
twelvechairs
I would agree but concerned on this

> Compatibility of the structure of AST nodes are not guaranteed.

Not sure if it means its going to be any more stable/complete than ruby_parser
/ ruby2ruby

------
ksec
There is another announcement from RubyKaigi 2018 related to performance.

Rubex - A Ruby-like language for writing Ruby C extensions.

[https://github.com/SciRuby/rubex](https://github.com/SciRuby/rubex)

------
himom
I wish though, that except for eval and exec, that the majority of Ruby code
could get an incremental/LTO JIT similar to HotSpot and a GC like C4 rather
than an inc gen GC.

------
blattimwind
> Unlike ordinary JIT compilers for other languages, Ruby’s JIT compiler does
> JIT compilation in a unique way, which prints C code to a disk and spawns
> common C compiler process to generate native cod e.

Oh dear god.

~~~
tbodt
What's the advantage over using LLVM's built-in JIT, or PyPy's JIT, or
generating machine code directly, or anything else that doesn't have the
overhead of spawning processes for compiling and linking? One of the goals
listed is minimizing the JIT compilation time.

~~~
emn13
LLVM clearly wasn't designed for JIT. Don't let those letters "VM" confuse
you; it's more like a machine abstraction than a virtual machine. And even
that is far from water-tight.

But that doesn't mean you can't use a conventional compiler stack like LLVM as
a JIT and get excellent code - it' just going to take its own sweet time doing
so.

Can anyone think of any reasonably common stacks using LLVM as a JIT? There's
mono, but that's a non-default mode; not sure if it's typically used. The
python unladen-swallow experiment failed. Webkit had a short-lived FLT
javascript optimization pass, but that was replaced by B3.

Which is just a long-winded way to suggest that LLVM is not likely to be ideal
as a JIT, at least based on what past projects have done.

(Not trying to imply that writing C to disk is better, but it may well be
simpler & more flexible - not worthless qualities for an initial
implementation).

~~~
eslaught
I use LLVM as a JIT via Terra [1]. It performs about as well as you'd expect
any other C compiler to perform. That is, if you do a bad job of code
generation and pass it a multi-MB file in a single function, well then of
course it's going to choke. But if you're optimizing tight loops and have
reasonable code generation, it's very good and you can get performance
comparable to a best-in-class C compiler without the overhead and headache
associated with calling out to an external program.

The main place where LLVM bites you is compatibility. There simply is none.
This is a constaint drain on your resources and a lot of projects can't afford
to keep up. There is even a project on LLVM's own home page which is was on
3.4 for a long time and has just recently upgraded to 3.8 [2].

But if the alternative is shelling out to a C compiler? I'll take LLVM any
day. The issue is not just the overhead of a call to an external program, it's
all the extra complexity that comes along with that. It is very, very easy for
this approach to break, especially when you consider the breadth of C
compilers that exist, and all the possible ways they can be configured. In
contrast, LLVM is "just" a library that you link to.

[1]: [http://terralang.org/](http://terralang.org/)

[2]: [http://klee.llvm.org/](http://klee.llvm.org/)

~~~
emn13
I'm a little skeptical about the costs complexity of an external program. You
may not need to support all those C compilers, but at least you have the
choice. And C is _extremely_ mature and stable. If you're generating code, you
probably don't need to use the latest not-so-well supported features; you may
well be able to have C code that compiles on almost any compiler from the last
3 decades without too much trouble. And while there will be more configuration
choices, it's not like raw LLVM has none.

If anything, I'd bet plain C is much _simpler_ because it hasn't changed much,
and is very unlikely to ever to anything very suprising on any future platform
- which cannot be said of raw LLVM.

And of course shelling out is a a bit of a hassle, but hey; it's a well-
trodden path on unix. It's not the fastest, greatest interop in the world, but
it's good enough for a lot of things.

(and wow- terra sounds impressive!)

~~~
eslaught
I agree with many of your points, in theory.

I'll just say that my views come mainly from experience, specifically ECL
(Embeddable Common Lisp, a CL implementation) and (this was further back, so
my memory is fuzzy) a tool for generating executables from Perl scripts. I
don't think I'm using an especially unusual setup, or unusual compilers, and I
would guess that these tools probably target a very narrow subset of C.
Despite this, my experience with these sorts of tools has been anything but
"works out of the box". On the contrary, there appear to be a great number of
degrees of freedom, even with standard-ish setups, that can trip up these
tools. Because of the additional layers of abstraction, the error messages you
get are very poor. Some header file is missing or in an unexpected place, or
worse some generated code fails to compile. As an end-user, it's basically
impossible to debug these in a reasonable way.

You can certainly have internal errors using LLVM, but in my experience fewer
of them are platform-dependent. Therefore there is a greater chance that
something that works for the developer will work for the user. Also, if error
handling is done properly, if a failure does occur it can often mapped back to
the original source program. This is much better as far as usability goes,
since the user almost never wants to debug some compiler's generated code.

------
karag
why ruby innovate and not python ?

~~~
_ZeD_
why not both? and btw, you may look at pypy if you like this kind of
innovations

~~~
geofft
In fact, one of the oldest JITted Ruby implementations is Topaz, which was
built on top of PyPy (i.e., it's a Python program that uses the PyPy
infrastructure to parse/JIT/run Ruby instead of Python).

------
jaequery
I wonder if Matz may consider even just adopting Crystal in the future,
considering it is almost 99% compatible with Ruby and has 10x-20x performance
gains out of the box.

~~~
jashmatthews
Crystal is far less compatible with Ruby than that. Simple methods/classes are
valid but everything after that is completely different.

~~~
TeddyDD
This. Some concepts and syntax are similar but they are quite different. I'm
not saying that in negative sense - static typing with type inference rocks.

------
stevebmark
Everything in Ruby happens at runtime. Even the definition `class X` becomes a
runtime `Class.new` invocation. It's imperative from the inside out. Even a
JIT is compiler won't and can't solve the fundamental flaws permanently baked
into the language. If you want performance, Ruby probably shouldn't be the
first tool you reach for.

~~~
stouset
This isn’t a flaw. It’s a tradeoff. And one that buys an incredibly useful
amount of flexibility.

~~~
stevebmark
It's a "tradeoff" in the way that not writing tests is a tradeoff

~~~
sametmax
Sure. Let's write a script, a website or analyse bio data together. You pick a
static language. I'll pick a dynamic one. See you tomorrow.

~~~
stevebmark
While my main concerns about Ruby aren't directly related to type systems or
static typing, at this point in my career, the speed at which I can hack out a
script in a language in 24 hours isn't related to how well designed I think
the language is.

