bundled_gems.rb: Add a fast path
[Bug #20641] `Gem::BUNDLED_GEMS.warning?` adds a lot of extra work on top of `require`. When the call end up atually loading code the overhead is somewhat marginal. However it's not uncommon for code to go some late `require` in some paths, so it's expected that calling `require` with something already required is somewhat fast, and `bundled_gems.rb` breaks this assumption. To avoid this, we can have a fast path that in most case allow to short-circuit all the heavy computations. If we extract the feature basename and it doesn't match any of the bundled gems we care about we can return very early. With this change `require 'date'` is now only 1.33x slower on Ruby 3.3.3, than it was on Ruby 3.2.2, whereas before this change it was at least 100x slower.
This commit is contained in:
parent
3a16971c06
commit
82aee1a946
Notes:
git
2024-07-22 08:33:25 +00:00
@ -34,6 +34,8 @@ module Gem::BUNDLED_GEMS
|
||||
"logger" => "3.5.0",
|
||||
}.freeze
|
||||
|
||||
SINCE_FAST_PATH = SINCE.transform_keys { |g| g.sub(/\A.*\-/, "") }.freeze
|
||||
|
||||
EXACT = {
|
||||
"kconv" => "nkf",
|
||||
}.freeze
|
||||
@ -92,6 +94,13 @@ module Gem::BUNDLED_GEMS
|
||||
def self.warning?(name, specs: nil)
|
||||
# name can be a feature name or a file path with String or Pathname
|
||||
feature = File.path(name)
|
||||
|
||||
if feature.include?("/")
|
||||
return unless SINCE_FAST_PATH[File.basename(feature, ".*")]
|
||||
else
|
||||
return unless SINCE_FAST_PATH[feature]
|
||||
end
|
||||
|
||||
# bootsnap expands `require "csv"` to `require "#{LIBDIR}/csv.rb"`,
|
||||
# and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`.
|
||||
name = feature.delete_prefix(ARCHDIR)
|
||||
|
35
test/test_bundled_gems.rb
Normal file
35
test/test_bundled_gems.rb
Normal file
@ -0,0 +1,35 @@
|
||||
require_relative "rubygems/helper"
|
||||
require "rubygems"
|
||||
require "bundled_gems"
|
||||
|
||||
class TestBundlerGem < Gem::TestCase
|
||||
def setup
|
||||
Gem::BUNDLED_GEMS::WARNED.clear
|
||||
end
|
||||
|
||||
def teardown
|
||||
Gem::BUNDLED_GEMS::WARNED.clear
|
||||
end
|
||||
|
||||
def test_warning
|
||||
assert Gem::BUNDLED_GEMS.warning?("rss", specs: {})
|
||||
assert_nil Gem::BUNDLED_GEMS.warning?("rss", specs: {})
|
||||
end
|
||||
|
||||
def test_no_warning_warning
|
||||
assert_nil Gem::BUNDLED_GEMS.warning?("some_gem", specs: {})
|
||||
assert_nil Gem::BUNDLED_GEMS.warning?("/path/to/some_gem.rb", specs: {})
|
||||
end
|
||||
|
||||
def test_warning_libdir
|
||||
path = File.join(::RbConfig::CONFIG.fetch("rubylibdir"), "rss.rb")
|
||||
assert Gem::BUNDLED_GEMS.warning?(path, specs: {})
|
||||
assert_nil Gem::BUNDLED_GEMS.warning?(path, specs: {})
|
||||
end
|
||||
|
||||
def test_warning_archdir
|
||||
path = File.join(::RbConfig::CONFIG.fetch("rubyarchdir"), "syslog.so")
|
||||
assert Gem::BUNDLED_GEMS.warning?(path, specs: {})
|
||||
assert_nil Gem::BUNDLED_GEMS.warning?(path, specs: {})
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user