Update: I'm switching my recommendation from rrails to rails-sh as the former supports REPL which is not the use case for rrails.Also patching does seem to add performance when combined with ruby environment variables, now reflected in the answer.
One possible reason may be this performance bug in ruby that has it call some code whenever "require" is used in the ruby code (more details here ). I ran in to this issue as well on my development box when developing with Rails (I use rails 3.2.6 on ruby 1.9.3p194 at the moment). The development environment runs on Ubuntu but this problem may happen on other operating systems because it's based on the interpreter.
While that bug is not fixed, there are two things I did to shave time from my ruby CLI. The first is to preload with rails-sh and the second is to use a popular ruby performance boosting patch to build an MRI ruby that is faster.
There are two libraries that do preloading nicely: rrails and rails-sh. Both are great but I will discuss rails-sh because it offers REPL support for commands like rails console
in the terminal and binding.pry
/debugger
in the code.
Setup rails-sh
I put it in my development group since that's where I use rails/rake commands often and need speed.
group :development do
#...
gem 'rails-sh'
end
Then install it :
bundle install --binstubs=./bundler_stubs
(I use binstubs to avoid 'bundle exec' in commands but that's optional)
Now just open a spare terminal to your rails project and run the rails-sh (add bundle exec
if you need to):
$ rails-sh
. .... ... .. ....... ............ ... .. .
. .. .. .. .... .... ...... .............. ...... .. .
. ... .... .... ....... ... ... ... .
. .. .. .. .... .... .......... .............. .. .. .
. .. .. .. .. .. ... ............ ... .. .
................................................................
v1.5.2
# require /home/yuvilio/ws/site/config/boot
# require /home/yuvilio/ws/site/config/application
# Rails.application.require_environment!
Rails.env: development
type `help` to print help
rails-sh(site)>
Now you can use rake and rails command in that prompt
rails-sh(site)> rails s
$ rails s
=> Booting Thin
=> Rails 3.2.6 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
>> Thin web server (v1.4.1 codename Chromeo)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:3000, CTRL+C to stop
Or to run a rake task like db:test:prepare:
rails-sh(site)> rake db:test:prepare
12.471001136sec
rails-sh(site)>
But is it fast? Well, on my machine (a core i5 laptop with 8gig RAM), the same rake db:test:prepare
took 12.5 seconds inside the rails-sh command (see above) compared to 34 seconds without it:
$ time rake db:test:prepare
real 0m34.796s
user 0m21.057s
sys 0m1.144s
$
The 22 second difference was that the rake command outside rails-sh had to load the rails environment before getting to the database, which is wasteful since it hadn't changed. The same applies for rails
commands.
Patched ruby
Another solution for MRI rubies, which is compatible with preloading and suggested in the rails performance guide, is to install a popular patch (falcon, railsexpress) on your ruby 1.9 and add some environment variables that use it.
I tested out the falcon and railsexpress patches (separately) on an rvm install and picked up similar performance in both cases.
$ rvm get head
$ rvm cleanup sources
$ rvm install ruby-1.9.3-p194 --reconfigure --name falcon --patch falcon --force-autoconf -j 3
$ rvm use ruby-1.9.3-p194-falcon
To make use of the patch
export RUBY_HEAP_MIN_SLOTS=1000000
export RUBY_HEAP_SLOTS_INCREMENT=1000000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_GC_MALLOC_LIMIT=1000000000
export RUBY_HEAP_FREE_MIN=500000
You can track which patches are available for which rubies in rvm here.