How To Get That Edge Ruby Faster-Loading-Hotness in Ruby 1.9.2 Now
A few days ago I told the story of ruby-head (MRI) getting 36% faster loading, perfect for tackling those file-heavy Rails 3 apps. Awesome for Ruby 1.9.3 but not so good for us now, right? Todd Fisher to the rescue! He's created a patch backporting the performance tweak to Ruby 1.9.2-p180.
Tip: If you're still on 1.8, check out The Ruby 1.9 Walkthrough, a mega screencast aimed at Ruby 1.8.7 developers who want to learn all about what's new, what's gone, and what's different in Ruby 1.9.2 and 1.9.3.
First, The Results
As the current production version of Ruby, a boost for Ruby 1.9.2-p180 should benefit most of you so I knew I had to share Todd's work as soon as I'd given it a test run. I ran the same benchmarks as in my earlier post and got a reduction in Rails 3 app load time of:
- 16.7% for the empty Rails 3 app
- 23.6% for the 'larger' in-production Rails 3 app
Only ~20% faster compared to ruby-head's 35%? That's actually good news! It means ruby-head (and so, hopefully, 1.9.3) has some extra performance boosts beyond the loading stuff - awesome! (Bear in mind in the previous post I benchmarked ruby-head with the patch against normal 1.9.2-p180.)
Now, The How
So how do you get this stuff? First, you need to be using RVM to manage your Ruby installs. You'll need to figure things out for yourself if you're compiling Ruby by hand. If you're using other forms of package management, you might find this all a bit 'hacky' and want to give it a miss.
Obligatory disclaimer: Don't do this unless you have a basic idea of what you're doing. And if your performance isn't improved, don't blame us. Boring bit over.
OK RVM users, do this:
curl https://raw.github.com/gist/1008945/7532898172cd9f03b4c0d0db145bc2440dcbb2f6/load.patch > /tmp/load.patch rvm get head # always good to make sure you're up to date with RVM rvm reload rvm install ruby-1.9.2-p180 --patch /tmp/load.patch -n patched rvm use ruby-1.9.2-p180-patched
Note: You can just use ruby-1.9.2-patched
but I'm playing it safe in the example ;-)
Note 2: Someone has reported that the above has resulted in an error at the patching stage. I've run it on two machines now without any problems but if you have problems, look at the log file RVM tells you to check out. It might give you a hint. Feel free to post a comment on this post too.
And now you're on the 'patched' Ruby 1.9.2. You'll need to run bundle again in your project(s) but in theory everything should work as before, just with faster loading.
So Todd Fisher just made your Rails 3 app start up somewhere around 20% faster without making you move away from a reliable, production version of Ruby. Buy the guy a beer when you see him next.
[ad] RailsKits is here to bring you great ready-made Rails code for you to use in your projects. More than just plugins, these starter kits can act as the foundation of your new Rails application. You can save hours of time, skipping the boring stuff and diving right into the code that makes your application different from all the rest.
June 8, 2011 at 4:42 am
Pretty impressive. I got this to work with no issues and there's a noticeable speed improvement on my MBP. I have guard/spork/growl running; previously when I saved a spec I'd have a couple seconds of wait time for the growl notification to appear. Now it seems like its nearly instant.
June 8, 2011 at 5:46 am
I'm getting the errors installing the patch as Mike in this gist - https://gist.github.com/53031fcff0f3258f0f90#comments
June 8, 2011 at 7:03 am
It installed ok, however my project is now throwing Psych errors: https://gist.github.com/1013931
Really hoping ruby team supports an officially supported 1.9.2-p181 with this patch. It probably would speed up Heroku dyno boot times quite a bit
June 8, 2011 at 11:49 am
I've tried it and it works... but it's way too slower than 1.8.7.
1.8.7:
Finished in 0.2067 seconds
21 examples, 0 failures, 3 pending
real 0m7.510s
user 0m4.940s
sys 0m2.430s
1.9.2:
Finished in 0.66704 seconds
21 examples, 0 failures, 3 pending
real 0m31.116s
user 0m28.450s
sys 0m2.160s
1.9.2-patched:
Finished in 0.39284 seconds
21 examples, 0 failures, 3 pending
real 0m17.468s
user 0m15.310s
sys 0m1.940s
And it's just a very simple app of 40-50 loc with some gems
Doing bdd with autotest it's just frustrating using 1.9.2, it takes too much time to run the test :(
June 8, 2011 at 12:02 pm
Got mine patched and running. Not a huge difference, but my spec suite ran in 5.93 secs before, and it now runs in 5.6 secs. Better than before I suppose.
Cheers!
June 8, 2011 at 12:51 pm
Nice to see this backported. However, there's no evidence here that the performance gap between this and head is due to additional performance boosts in head. Perhaps the patch has different runtime characteristics in 1.9.2 and head (it was written for head after all). Or perhaps head was more heavily affected by the issue and thus the patch had a much larger influence. I'm just reluctant to say "there's a difference and it must be because head is faster!"
June 8, 2011 at 1:49 pm
Joel: Surprised you didn't see better on a small suite (the one for my larger app doesn't get a massive boost but it's 2 minutes long so a few seconds on loading is nothing). Guessing you don't have many entries in the Gemfile but quite a few unit tests? (So less loading to improve.)
June 8, 2011 at 1:50 pm
@Jacques: The problem might be related to the site hosting the YAML library being down last night so RVM was skipping it on the install. Was a common problem with RVM users last night :-(
June 8, 2011 at 3:22 pm
It's failing to compile in load.c for me:
gcc -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -\
Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe -I. -I.ext\
/include/x86_64-darwin10.7.0 -I./include -I. -DRUBY_EXPORT -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE \
-o load.o -c load.c
load.c: In function ‘get_loaded_features_hash’:
load.c:99: error: ‘rb_vm_t’ has no member named ‘loaded_features_hash’
load.c:102: error: ‘rb_vm_t’ has no member named ‘loaded_features_hash’
load.c: In function ‘get_filename_expansion_hash’:
load.c:112: error: ‘rb_vm_t’ has no member named ‘filename_expansion_hash’
load.c:115: error: ‘rb_vm_t’ has no member named ‘filename_expansion_hash’
load.c: In function ‘rb_feature_p’:
load.c:292: error: ‘loadable_ext’ undeclared (first use in this function)
load.c:292: error: (Each undeclared identifier is reported only once
load.c:292: error: for each function it appears in.)
load.c: In function ‘Init_load’:
load.c:773: error: ‘j’ undeclared (first use in this function)
make: *** [load.o] Error 1
June 8, 2011 at 3:34 pm
My bad. It turns out I was getting the same error DrNic was, and the solution (however strange it is) was to rm the patch, rm ~/.rvm/archives/ruby-1.9.2-p180*, rm ~/.rvm/src/ruby-1.9.2-p180*, then re-fetch the patch and restart the build.
June 8, 2011 at 7:15 pm
Did the install as outlined with no issues. Just running spec suite to compare gave me this:
=> ruby-1.9.2-p0 [ x86_64 ]
Finished in 260.15 seconds
1762 examples, 0 failures, 22 pending
=> ruby-1.9.2-p180-patched [ x86_64 ]
Finished in 273.49 seconds
1762 examples, 0 failures, 22 pending
June 8, 2011 at 9:40 pm
Pretty impressive!
1.9.2-p136 :20.32s user 3.54s system 81% cpu 29.322 total
1.9.2-p180-patched: 9.96s user 3.48s system 70% cpu 19.003 total
Although not enough to say good-bye to spork.
June 8, 2011 at 9:55 pm
If you are unable to install the patched ruby and the error log contains messages about failed hunks, then you may be able to fix the problem by running "rvm cleanup all" before you install the patched Ruby.
If you're having issues with Psych, you can edit your config/environment.rb file in Rails and add this line:
YAML::ENGINE.yamler = 'syck'
The problem is likely that Ruby is using Psych for YAML parsing, and the 1.9.2 version of Psych can't handle merge keys (eg. <<: *default)
June 8, 2011 at 10:51 pm
You might also consider using the railsexpress patchset for 1.9.2 (https://github.com/skaes/rvm-patchsets).
It also contains 1.9.2 versions of my GC patches (which are contained in REE).
June 9, 2011 at 5:36 am
Thanks Matt Royal! "rvm cleanup all" did the trick for me.
June 9, 2011 at 11:16 am
For me, the patch dropped loading the Rails environment from 18.5 seconds to 12.5 seconds.
I WANT MORE! :)
June 10, 2011 at 9:35 am
This crashes for me on ttfunk, especially on the following line:
Hash[*(0..255).zip(0..255).flatten]
When trying it out it seems the culprit is the Range#zip(Range)
The full crash log:
https://gist.github.com/1018547
June 11, 2011 at 6:02 am
Sory, not a comment, it's only to signal this article to
your attention :
http://chris.wailes.name/?page_id=97
by
June 11, 2011 at 8:04 am
Tried it with my 2.3.x project - got ~23% performance improvement on project startup. Good work, thanks!
June 11, 2011 at 8:40 am
Interesing, but patches from Stefan Kaes gave me better performance improvement (again, on 2.3.x project):
Start with plain 1.9.2-180: 8.3sec
Start with plain 1.9.2-180-patched: 6.4sec
Start with plain 1.9.2-180-railsexpress: 5.9sec
So, Stefan's patch for ruby 1.9.2 gave me ~29% startup time increase!
June 14, 2011 at 2:15 pm
I've tried this on an medium sized rails3 app and could see atleast 20-30% improvement for rails server and rake tasks
June 14, 2011 at 5:52 pm
Seems this is really important issue :-) I have also investigated it some time ago and finally wrote a blog post with patch about it. I measured up to 40% improvement on load time, while entire patch changes only four lines.
Here are the details: http://www.lunarlogicpolska.com/blog/2011/06/14/tracing-processes-for-fun-and-profit.html
June 17, 2011 at 4:53 pm
@Jarosław: I hope your patch will get merged upstream. It got me biiig improvement - I don't need spork b/c specs now start so much faster.
July 7, 2011 at 12:04 pm
Our Rails app has 49 gems, and with that patch, the loading time has been shortened from 51.830s to 23.269s. Really impressive.
I really hope this one will get backported to 1.9.2.