summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2020-07-06 15:18:05 +0200
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2020-07-31 21:07:19 +0900
commit76722c4928d92fa6cc4a927203eab8a036516e23 (patch)
treef330674c42b4df887384c04593d44bc7e24e6392
parent832fe778796026389f05330242795a004e442360 (diff)
[rubygems/rubygems] Optimize Gem.already_loaded?
Profiling a simple `ruby -e '1'` I see: ``` ================================== Mode: wall(10) Samples: 3414 (55.10% miss rate) GC: 856 (25.07%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 689 (20.2%) 669 (19.6%) Gem.already_loaded? 462 (13.5%) 462 (13.5%) (marking) 393 (11.5%) 393 (11.5%) (sweeping) 815 (23.9%) 365 (10.7%) Gem::Specification.load 1050 (30.8%) 156 (4.6%) Gem.register_default_spec 100 (2.9%) 84 (2.5%) Gem::Specification#files 64 (1.9%) 64 (1.9%) Gem::BasicSpecification#internal_init 136 (4.0%) 59 (1.7%) <top (required)> 2312 (67.7%) 58 (1.7%) <top (required)> 57 (1.7%) 57 (1.7%) RbConfig.expand 81 (2.4%) 55 (1.6%) Gem::Requirement.parse 191 (5.6%) 51 (1.5%) <top (required)> 128 (3.7%) 47 (1.4%) Gem::Requirement#initialize 41 (1.2%) 41 (1.2%) Gem.suffix_regexp 229 (6.7%) 35 (1.0%) <module:Gem> 260 (7.6%) 34 (1.0%) Kernel#require ``` So clearly `Gem.already_loaded?` is a major hotspot. After this optimization, it's down to: ``` ================================== Mode: wall(10) Samples: 2653 (58.21% miss rate) GC: 718 (27.06%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 416 (15.7%) 416 (15.7%) (marking) 715 (27.0%) 312 (11.8%) Gem::Specification.load 299 (11.3%) 299 (11.3%) (sweeping) 279 (10.5%) 279 (10.5%) Gem.already_loaded? 564 (21.3%) 106 (4.0%) Gem.register_default_spec 95 (3.6%) 80 (3.0%) Gem::Specification#files 72 (2.7%) 72 (2.7%) Gem::BasicSpecification#internal_init 129 (4.9%) 58 (2.2%) <top (required)> 53 (2.0%) 53 (2.0%) RbConfig.expand 1697 (64.0%) 52 (2.0%) <top (required)> 68 (2.6%) 49 (1.8%) Gem::Requirement.parse 183 (6.9%) 48 (1.8%) <top (required)> 112 (4.2%) 44 (1.7%) Gem::Requirement#initialize 220 (8.3%) 33 (1.2%) <module:Gem> 250 (9.4%) 32 (1.2%) Kernel#require ``` The idea is that the vast majority of the time `already_loaded?` won't match anything. So by first looking for candidate paths that `end_with?` the file we look for, we save `default_gem_load_paths.size` iterations and string concatenations. https://github.com/rubygems/rubygems/commit/c60ce88d49
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3379
-rw-r--r--lib/rubygems.rb4
1 files changed, 2 insertions, 2 deletions
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index e72d62b786..8e23c32296 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1300,8 +1300,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
private
def already_loaded?(file)
- default_gem_load_paths.find do |load_path_entry|
- $LOADED_FEATURES.include?("#{load_path_entry}/#{file}")
+ $LOADED_FEATURES.any? do |feature_path|
+ feature_path.end_with?(file) && default_gem_load_paths.any? {|load_path_entry| feature_path == "#{load_path_entry}/#{file}" }
end
end