Greg
Greg

Reputation: 2719

Why is rspec so slow under rake? ruby_noexec_wrapper?

I'd been having problems with my spec code taking a lot longer than expected to run, but when I tried to run them under rspec-prof, the problem seemed to go away. Eventually I tracked the difference down to running rake natively compare to running it under an interpreter.

Running just rake takes 75 seconds, but running ruby $(which rake) takes only 12 seconds. That's over five times as quicker. Take a look:

$ rake
~/.rvm/rubies/ruby-1.9.2-p320/bin/ruby -w -S rspec spec/args_spec.rb spec/levels_spec.rb spec/opts_spec.rb spec/run_spec.rb spec/split_spec.rb spec/unit_spec.rb
~/.rvm/gems/ruby-1.9.2-p320/gems/bundler-1.2.3/lib/bundler/source.rb:516: warning: method redefined; discarding old revision
..................................................

Finished in 1 minute 14.39 seconds
50 examples, 0 failures

$ ruby `which rake`
~/.rvm/rubies/ruby-1.9.2-p320/bin/ruby -w -S rspec spec/args_spec.rb spec/levels_spec.rb spec/opts_spec.rb spec/run_spec.rb spec/split_spec.rb spec/unit_spec.rb
..................................................

Finished in 12.88 seconds
50 examples, 0 failures

Looking at the contents of the rake "wrapper binary" shows in the "#!" line that it is running under the interpreter - ruby_noexec_wrapper - and sure enough running the command as:

ruby_noexec_wrapper $(which rake)

Gives the same slow 75 seconds run.

Any ideas why this should be the case?

Apart from avoiding running rake directly is there anything that can be done to improve it? Since that's a standard way to wrap gems to be binaries, isn't that potentially slowing down all gem-packaged tools?

Upvotes: 1

Views: 189

Answers (1)

Jon Cairns
Jon Cairns

Reputation: 11951

Let's take a look at the ruby_noexec_wrapper file (rvm 1.16.17):

#!/usr/bin/env ruby

original_file=ARGV[0]
ARGV.shift
$PROGRAM_NAME=original_file

require 'rubygems'
begin
  require 'rubygems-bundler/noexec'
rescue LoadError
  warn "unable to load rubygems-bundler/noexec" if ENV.key?('NOEXEC_DEBUG')
end

eval File.read(original_file), binding, original_file

As far as I can see, the two warning areas are the two require statements. The first, require 'rubygems', is not likely to be a problem, as ruby 1.9+ does this automatically.

I think the problem is in require 'rubygems-bundler/noexec'. If you take a look at what it's doing you can see that it's setting up bundler. This involves requiring gems, which is likely to be the source of your slow startup.

Gems shouldn't do a whole lot when they are loaded, but unfortunately many of them make some mistakes in that area. The only way to solve this is to try and work out which gems are causing the majority of the slowness and find alternatives where possible.

Upvotes: 1

Related Questions