[前][次][番号順一覧][スレッド一覧]

ruby-changes:41867

From: tenderlove <ko1@a...>
Date: Fri, 26 Feb 2016 08:22:54 +0900 (JST)
Subject: [ruby-changes:41867] tenderlove:r53941 (trunk): Reduce system calls by activating the `did_you_mean` gem.

tenderlove	2016-02-26 08:23:30 +0900 (Fri, 26 Feb 2016)

  New Revision: 53941

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53941

  Log:
    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 #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #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 #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #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 #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #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 #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #1 at DIF offset 24
    dtrace: error on enabled probe ID 3 (ID 826: syscall::stat64:entry): invalid user access in action #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.

  Modified files:
    trunk/ChangeLog
    trunk/gem_prelude.rb
Index: gem_prelude.rb
===================================================================
--- gem_prelude.rb	(revision 53940)
+++ gem_prelude.rb	(revision 53941)
@@ -1,7 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/gem_prelude.rb#L1
 if defined?(Gem)
   require 'rubygems.rb'
   begin
+    gem 'did_you_mean'
     require 'did_you_mean'
-  rescue LoadError
+  rescue Gem::LoadError, LoadError
   end if defined?(DidYouMean)
 end
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 53940)
+++ ChangeLog	(revision 53941)
@@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Feb 26 08:11:58 2016  Aaron Patterson <tenderlove@r...>
+
+	* gem_prelude.rb: Reduce system calls by activating the `did_you_mean`
+	  gem before requiring the 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.
+
 Thu Feb 25 19:04:13 2016  Martin Duerst  <duerst@i...>
 
 	* enc/unicode/case-folding.rb: Adding possibility for debugging output

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]