diff options
author | Jean Boussier <jean.boussier@gmail.com> | 2020-07-06 15:18:05 +0200 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2020-07-31 21:07:19 +0900 |
commit | 76722c4928d92fa6cc4a927203eab8a036516e23 (patch) | |
tree | f330674c42b4df887384c04593d44bc7e24e6392 /lib/rubygems.rb | |
parent | 832fe778796026389f05330242795a004e442360 (diff) | |
download | ruby-76722c4928d92fa6cc4a927203eab8a036516e23.tar.gz |
[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
Diffstat (limited to 'lib/rubygems.rb')
-rw-r--r-- | lib/rubygems.rb | 4 |
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 |