-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Could boot performance be improved? Caching default gems perhaps? #3799
Comments
So funny, I'm working on that exact path 🤣. I have this, which I believe is the same idea: commit 0441af11bcf6d1418f52f0c0dd2c87c60d694e8b
Author: David Rodríguez <deivid.rodriguez@riseup.net>
Date: Wed Jul 8 09:09:31 2020 +0200
Load a marshaled version of the default specs map if available
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 8bc0ef4b74..12936671db 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1242,8 +1242,14 @@ def register_default_spec(spec)
# Loads the default specifications. It should be called only once.
def load_default_specs
- Gem::Specification.each_spec([default_specifications_dir]) do |spec|
- register_default_spec(spec)
+ if File.exist?(marshaled_default_spec_file)
+ @path_to_default_spec_map = Marshal.load read_binary(marshaled_default_spec_file)
+ else
+ Gem::Specification.each_spec([default_specifications_dir]) do |spec|
+ register_default_spec(spec)
+ end
+
+ File.open(marshaled_default_spec_file, "w") {|io| Marshal.dump @path_to_default_spec_map, io }
end
end
@@ -1319,6 +1325,9 @@ def default_gem_load_paths
@default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1]
end
+ def marshaled_default_spec_file
+ File.join(dir, "default_specs.#{marshal_version}")
+ end
end
##
commit 1ee905c8eea7efa2257f1acdde3a27074c5ac3e5
Author: David Rodríguez <deivid.rodriguez@riseup.net>
Date: Tue Jul 7 20:11:30 2020 +0200
Move `Gem::Specification.load_defaults` to `Gem.load_default_specs`
And deprecate the former. Makes sense I believe for upcoming work.
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 1a70ee9d0a..8bc0ef4b74 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1238,6 +1238,15 @@ def register_default_spec(spec)
end
end
+ ##
+ # Loads the default specifications. It should be called only once.
+
+ def load_default_specs
+ Gem::Specification.each_spec([default_specifications_dir]) do |spec|
+ register_default_spec(spec)
+ end
+ end
+
##
# Find a Gem::Specification of default gem from +path+
@@ -1358,7 +1367,7 @@ def default_gem_load_paths
##
# Loads the default specs.
-Gem::Specification.load_defaults
+Gem.load_default_specs
require 'rubygems/core_ext/kernel_gem'
require 'rubygems/core_ext/kernel_require'
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index e6ecc7649a..3c83494b8e 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -845,15 +845,14 @@ def self._resort!(specs) # :nodoc:
end
end
- ##
- # Loads the default specifications. It should be called only once.
+ def self.load_defaults # :nodoc:
+ Gem.load_default_specs
+ end
- def self.load_defaults
- each_spec([Gem.default_specifications_dir]) do |spec|
- # #load returns nil if the spec is bad, so we just ignore
- # it at this stage
- Gem.register_default_spec(spec)
- end
+ class << self
+ extend Gem::Deprecate
+
+ rubygems_deprecate :load_defaults, "Gem.load_default_specs"
end |
Oh! That's awesome. I'll ignore that area then, and focus on other ideas. Should I close this issue? |
I'll definitely tag you on the PR, which will close this, so we call leave this opened 👍. I believe we can assume default specs are immutable, yeah. Regarding the cache location, we could use |
Refs: https://bugs.ruby-lang.org/issues/18568 and #4199 |
Sorry if this was discussed elsewhere, I tried to search for previous discussions but given how generic the subject is I couldn't find anything.
Context
As many people know, Rubygems initialization is the biggest part of MRI's boot:
So (on my machine) "raw" MRI initialization is
29ms
, and rubygems adds47ms
to it.When profiling, we can see that a large part of that comes from loading default gems:
If I comment out
Gem::Specification.load_defaults
, the overhead is down to26ms
:And most of that is in
each_spec([Gem.default_specifications_dir])
.Ideas
This makes me wonder what kind of assumptions we could make about default gems. Can we assume they are immutable? If so couldn't we cache all these specs in a single marshal dump file rather than evaluate all the default gems (55 on 2.8.0-dev) ?
I tried a very crude hack on my machine:
With the following result:
So
16ms
faster, which is about34%
ofrubygems
load time.Questions
So the main question here is what would it take to move this from a crude hack to an acceptable patch.
@deivid-rodriguez any thoughts on this?
The text was updated successfully, but these errors were encountered: