
Ruby Deoptimization Engine - ksec
https://github.com/ruby/ruby/pull/1419
======
rubiquity
If I understand the implementation correctly, this seems like it has a low
ratio of complexity to performance improvements. It will be interesting to see
if this ends up landing in MRI. I'm anxious to see some non-micro benchmarks
against "real world" Ruby, which basically means the Rails test suite, start
up time, etc.

My only concern would be what kind of impact this has on memory usage. Having
all of those in memory copies of method implementations hanging around
probably comes at a cost. But in general the world seems to be OK with trading
memory for speed these days. If Ruby is twice as fast for less than twice the
memory then we can easily consider it a win.

Anecdotally, it seems like servers these days have plenty of RAM to spare
relative to CPUs anyway. A semi-recent Rails app that ran on AWS EC2
m4.xlarge's with 24 Puma workers only used 5.5GB of the available 16GB of RAM.

It also looks like the spirit of this optimization comes from the work Chris
Seaton and others have been doing with Ruby and the Graal VM. It's great to
see work like that having an impact on MRI.

~~~
olivierlacan
Check out [https://rubybench.org/benchmarks](https://rubybench.org/benchmarks)
for Rails, Ruby, and Bundler benchmarks on every commit and release to either
project.

If you want Rails-specific benchmarks for Ruby commits I suggest the
`discourse_` benchmarks that are running specific chunks of the open-source
Discourse Rails app:
[https://rubybench.org/ruby/ruby/commits?result_type=discours...](https://rubybench.org/ruby/ruby/commits?result_type=discourse_home)

~~~
netghost
Thanks for the link, this is an excellent resource.

I really appreciate this view for the rails commits:
[https://rubybench.org/rails/rails/commits/overview](https://rubybench.org/rails/rails/commits/overview)

------
whistlerbrk
I've posted this link a number times on HN, but for more wonderfully written
background on this, read Chris Seaton's blog here:
[http://chrisseaton.com/rubytruffle/deoptimizing/](http://chrisseaton.com/rubytruffle/deoptimizing/)

------
qwertyuiop924
Wait, so what is this doing? I'm very confused.

~~~
Twirrim
[http://chrisseaton.com/rubytruffle/deoptimizing/](http://chrisseaton.com/rubytruffle/deoptimizing/)
mentioned above gives an excellent explanation. I was completely confused by
the name.

"In Ruby..." [we could have]... " deoptimization. It allows us to reverse the
just-in-time compilation process and go back to a simpler interpreter where
all the checks Ruby needs are explicit, all the objects really exist, and we
have code paths to handle anything."

It seems like Ruby has a whole lot of features that actually make optimising
it very difficult (monkey patching et al), and this is their attempt to work
around it.

~~~
qwertyuiop924
...You know, they could just limit monkey-patching, and drop call/cc and a few
other features (not having call/cc opens a lot of options), and they'd have a
dramatically easier system to work with, right?

When was the last time somebody used call/cc in ruby code, anyways? By current
implementation, it's only useful for thought experiments and toys, and we have
Scheme for that.

In short, deoptimization seems like a case of solving one of the sinister
black tendrils of the problem, not the root cause.

~~~
onetwotree
The problem with limiting monkey-patching is that it's used extensively and
with great variety in Rails (and other popular Ruby projects).

Monkey patching, done correctly, will "settle" over time. That is, once your
rails app has called all the dynamic finder methods it's ever going to use,
and `require`d all of the `active_support` extensions it'll need, it's done
monkey patching. Of course, there are programming mistakes that can open a
huge bag of worms, such as using `OpenStruct`s. Generally, anything that will
smash the global method cache[1] is also going to require the kind of `iseq`
deoptimization that this pull is about (in fact, smashing the global method
cache is a simple case of deoptimization).

This is why deoptimization is so useful - it's almost never going to happen
after your app has settled, but it's necessary to maintain correctness while
`active_support` is being loaded and adding all of those yummy methods to core
classes.

`call_cc` can go to hell though - I've never seen a program that uses it ;-)

[1]
[https://github.com/charliesome/charlie.bz/blob/master/posts/...](https://github.com/charliesome/charlie.bz/blob/master/posts/things-
that-clear-rubys-method-cache.md)

~~~
qwertyuiop924
Yeah, but there's got to be a less needlessly overcomplicated way of doing
this. It's ridiculous.

As for call_cc (or to use its "real" name call/cc, or call-with-current-
continuation), my usual response to those that propose dropping call/cc
(usually proposing shift/reset or similar as a replacement) is "over my dead
body," but that's Scheme: supporting weird experiments is part of Scheme's
job, and there's at least one high-quality implementation of Scheme that uses
Cheney-on-the-MTA compilation, which makes call/cc fast enough for Real Work.
In ruby, the situation is different: call/cc is slow, expensive, and Ruby is a
language for getting stuff done, not academic experiments about control
structure.

