8

This is a bit of a follow-up from a previous question on improving rails console loading time.

The first great suggestion was to figure out which gems take too long.

Next answer, suggested using :require => nil and loading those gems later.

With some gems however, it's not entirely clear how to accomplish this without breaking things. Here's a list of our 'biggest offenders', I wonder if someone can suggest the best approach to loading them only when necessary?

require gon: 2.730000 (2.870059)
require omniauth-openid: 1.410000 (1.503858)
require cancan: 2.640000 (2.707467)
require fog: 2.730000 (2.846530)
require activeadmin: 3.650000 (3.923877)

and of course there are many more that take around 1 second or less, which also adds up... but at least removing the big ones will already improve things.

how can I selectively load gems later to make rails load faster?

Community
  • 1
  • 1
gingerlime
  • 5,206
  • 4
  • 37
  • 66

1 Answers1

14

While not a direct answer to your question, there are two things you might try:

First, have you tried the Falcon patches for 1.9.3? The patches include some pretty significant load time improvements.

If you're using RVM, you can do a quick-and-dirty install with

rvm install 1.9.3 --patch falcon -n falcon

Second, make sure you're setting GC tuning environment variables. Ruby, by default, allocates GC parameters that are appropriate for small scripts, but not for full Rails apps. Here are my settings, though you'd want to derive your own based on your application's needs:

% env | grep RUBY_
RUBY_HEAP_MIN_SLOTS=800000
RUBY_HEAP_FREE_MIN=100000
RUBY_HEAP_SLOTS_INCREMENT=300000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GC_MALLOC_LIMIT=79000000

And my results using ruby 1.9.3-p286:

                    Stock     Stock+GC  Falcon   Falcon+GC
                    27.13     8.43      8.63     6.69
Stock       27.13   100.00%   31.07%    31.81%   24.66%
Stock+GC    8.43    321.83%   100.00%   102.37%  79.36%
Falcon      8.63    314.37%   97.68%    100.00%  77.52%
Falcon+GC   6.69    405.53%   126.01%   129.00%  100.00%

Setting the GC tuning parameters has the biggest improvement, but we can get yet another ~26% improvement performance by using the falcon patches. The combination of the falcon patches plus the GC parameters results in over a 75% reduction in boot time.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
  • Wow. Thanks. This looks very promising. Still relatively new to ruby/rails, but I'm using a compiled version of ruby, so will have to figure out how to get this patch compiled and then try to tune those GC params (also noticed the link you included mentions [zeus](https://github.com/burke/zeus) which also sounds amazing). I'll report back when I hopefully get this rolling. – gingerlime Oct 27 '12 at 20:18
  • This is quite amazing. The Falcon patches dropped down startup time from around 50 seconds to 13 seconds, and then further down to around 11 seconds with these GC parameters. Quite a huge boost! Hope this patch doesn't break anything but otherwise it looks awesome. Thanks!! – gingerlime Oct 27 '12 at 21:30
  • p.s. how did you generate these comparative results? – gingerlime Oct 27 '12 at 21:31
  • I was just running `time rails runner ""`, which bootstraps the Rails environment and then doesn't run any code, so it immediately exits. – Chris Heald Oct 27 '12 at 23:13
  • Thanks, and sorry I wasn't clear. I meant to ask about the comparison table showing the difference in percentage between all four options. – gingerlime Oct 28 '12 at 12:29
  • 1
    Oh, I just did that in a spreadsheet. [Here it is in GDocs](https://docs.google.com/spreadsheet/ccc?key=0Aqxu-bQf_3O5dEpvRlNPcjJlYldPWmF2R09xTHRlUUE). – Chris Heald Oct 28 '12 at 13:14
  • Thanks again for this Chris. This not only helped us loading rails faster, but also resolve [some strange slowness with redis](http://gist.io/3993155). – gingerlime Nov 01 '12 at 11:44
  • Great writeup. The GC will indeed get you if you're not careful. You might look at Newrelic if you aren't already using it; it'll instrument your GC passes and show you how much of your request time is being spent in GC passes. You can get additional real-world benefit by using something like http://unicorn.bogomips.org/Unicorn/OobGC.html to do garbage collection outside of your normal request cycle, improving user-facing response times. – Chris Heald Nov 01 '12 at 16:03
  • Thanks again Chris. So much useful stuff!! Am thinking of switching to unicorn from passenger anyway, so this is one more incentive. I saw some newrelic graphs showing GC stats, but am wondering if retrieving GC stats is possible without it? (we're [feeding statsd/graphite](http://37signals.com/svn/posts/3091-pssst-your-rails-application-has-a-secret-to-tell-you) for most of our measurements currently). – gingerlime Nov 01 '12 at 22:26
  • Yeah, you can collect the stats manually. See http://www.ruby-doc.org/core-1.9.3/GC.html for the details. Newrelic is worth every penny, though. :) – Chris Heald Nov 01 '12 at 22:28