Skip to content

Commit 4102031

Browse files
committed
Reduce system calls by activating the did_you_mean gem.
Activating the gem puts the gem on the load path, where simply requiring the file will search every gem that's installed until it can find a gem that contains the `did_you_mean` file. Calling RubyGems' `require` will search each installed gem until it can find one that contains the file it should require. This means that the more gems you have installed, the longer it can take to require that gem. To see this in action, lets compare the number of `stat` calls for a "bare require" vs the number of `stat` calls for a require that follows a gem activation by using these two programs: ``` [aaron@TC rubygems (master)]$ cat req_dym.rb begin require 'did_you_mean' rescue LoadError end [aaron@TC rubygems (master)]$ cat gem_dym.rb begin gem 'did_you_mean' require 'did_you_mean' rescue Gem::LoadError, LoadError end ``` The first program just requires the `did_you_mean` gem, where the second one activates the gem, then requires it. We can count the number of `stat` calls using `dtrace`: ``` [aaron@TC rubygems (master)]$ ruby -v ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15] [aaron@TC rubygems (master)]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --disable-did_you_mean req_dym.rb" | wc -l dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 283 [aaron@TC rubygems (master)]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --disable-did_you_mean gem_dym.rb" | wc -l dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 13 ``` The "bare require" version does over 10x the number of stat calls compared to the "gem, then require" version. Of course the number for the first one depends on the number of gems you have installed that sort before the `did_you_mean` gem. Lets also look at trunk Ruby: ``` [aaron@TC rubygems (master)]$ ruby -v ruby 2.4.0dev (2016-02-25 trunk 53940) [x86_64-darwin15] [aaron@TC rubygems (master)]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --disable-did_you_mean req_dym.rb" | wc -l dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 2325 [aaron@TC rubygems (master)]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --disable-did_you_mean gem_dym.rb" | wc -l dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action ruby#1 at DIF offset 24 685 ``` This change will reduce the number of `stat` calls on trunk Ruby too, but since this installation doesn't have the `did_you_mean` gem, RubyGems is still reading every gem spec file so that it can raise a `Gem::LoadError` exception with a nice error message. If we can modify RubyGems a little, it may be possible to drop the number of stat calls even on a Ruby installation that doesn't have the `did_you_mean` gem. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53941 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 5fa5b50 commit 4102031

File tree

2 files changed

+10
-1
lines changed

2 files changed

+10
-1
lines changed

ChangeLog

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
Fri Feb 26 08:11:58 2016 Aaron Patterson <[email protected]>
2+
3+
* gem_prelude.rb: Reduce system calls by activating the `did_you_mean`
4+
gem before requiring the gem. Activating the gem puts the gem on
5+
the load path, where simply requiring the file will search every gem
6+
that's installed until it can find a gem that contains the
7+
`did_you_mean` file.
8+
19
Thu Feb 25 19:04:13 2016 Martin Duerst <[email protected]>
210

311
* enc/unicode/case-folding.rb: Adding possibility for debugging output

gem_prelude.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
if defined?(Gem)
22
require 'rubygems.rb'
33
begin
4+
gem 'did_you_mean'
45
require 'did_you_mean'
5-
rescue LoadError
6+
rescue Gem::LoadError, LoadError
67
end if defined?(DidYouMean)
78
end

0 commit comments

Comments
 (0)