
Patching Rails Performance - strzalek
http://engineering.heroku.com/blogs/2015-08-06-patching-rails-performance/
======
jordanthoms
Speed improvements are always nice, but the big improvement for us came from
moving from 1x and 2x dynos to Performance dynos. CPU performance on the 1x
and 2x dynos was highly inconsistent, and would suddenly become abysmal for
periods of 5-10 minutes or more - and due to random routing, the backed up
dyno would keep on getting requests until the requests start timing out.

------
schneems
I wrote the patch and the article, do you have any questions related to
either?

~~~
nirvdrum
I've been impressed with the performance work you've been doing across the
board. But in these sorts of write-ups (and the corresponding issue trackers),
it'd be very helpful to qualify with which version of Ruby you're using. I've
surmised it's MRI, but even then different MRI versions can have different
performance profiles. It'd be helpful to know what your GC tuning looks like,
too. Particularly in cases where object allocation is determined to be a
factor.

Anyway, this is all good stuff and I don't doubt there's an improvement. A
little expansion on the methodology would just make it all the more valuable.

Tangential note: In one of the commit comments there's an exchange about the
performance of `any?` and it links to MRI source. However, it links to a line
in master, so the link will eventually fall out of date. If you press 'y' in
Github it'll change the URL to one with a SHA in it. Or maybe pick the release
tag so the link doesn't change as the file updates.

~~~
schneems
> I've been impressed with the performance work you've been doing across the
> board

Thanks!

For all the tests I used MRI Ruby 2.2.2. Unless otherwise noted, I almost
exclusively use the most recently released MRI Ruby version for testing. There
shouldn't be a huge difference in most recent Ruby versions. The only thing
that comes to mind is that `String#freeze` existed in older versions but was a
method call, and not implemented as a parsing optimization (i.e. it would
still allocate a string) however I believe that's been in there for a few
years. Maybe the generational GC might have an impact.

> It'd be helpful to know what your GC tuning looks like, too.

I used stock GC settings for all the benchmarks

``` $ env | grep GC # nothing here ```

> A little expansion on the methodology would just make it all the more
> valuable.

The patch does have some more specifics than the post, especially the commits.
I used benchmark/ips in some of them to demonstrate specifics problems. I can
do a larger write up on specific methodology, if you think that would be
interesting.

> If you press 'y'

Thanks, i've been trying to get in the habit of doing so, that's a good tip.

~~~
nirvdrum
> For all the tests I used MRI Ruby 2.2.2. Unless otherwise noted, I almost
> exclusively use the most recently released MRI Ruby version for testing.

Good to know. I guess I'm suggesting that specifically calling that out in the
text will help it stand the test of time. Otherwise the reader needs to cross-
reference the date with the MRI release list.

And really, this is all I was looking for in the methodology. The post covers
what you did in pretty good detail. The GC thing was something I was curious
about just because that's ping-ponged quite a bit throughout the 2.x releases.

Thanks again!

------
matthewcford
A lot of time according to new relic is spent in
Middleware/Rack/ActionDispatch::Routing::RouteSet#call on one of our Rails
apps on Heroku. Any ideas on what might be the cause? (I'm within memory
limits standard-2x)

~~~
schneems
Whooops responded with old account. If you run `$ env RAILS_ENV=production
rake middleware` you'll see that your final app that gets mounted is actually
the "routes" of your app.

    
    
        run CodeTriage::Application.routes
    
    

Essentially that RouteSet#call wraps every piece of code you've ever written
for your app. I think that newrelic is reporting that is the entry point to
your app code which makes sense that it takes the longest amount of time.

For a better view of request break down I would recommend checking out
[https://github.com/MiniProfiler/rack-mini-
profiler](https://github.com/MiniProfiler/rack-mini-profiler). You'll not only
see where request time is being spent, you'll see how it "stacks up". The
flame graphs are pretty useful check out
[http://www.nateberkopec.com/2015/08/05/rack-mini-profiler-
th...](http://www.nateberkopec.com/2015/08/05/rack-mini-profiler-the-secret-
weapon.html) for more info.

------
kentor
I've stopped doing ruby dev, but boy do I not miss mutable strings.
Javascript/Python's got that part right. String interning is a godsend.

~~~
tekknolagi
You can do string interning with Ruby. You just use symbols.

~~~
kentor
No. String#freeze exists for a reason.

