[rubygems/rubygems] Optimize allocations in Gem::Version
From running in a random rails app I have locally, here are the changes 1) for `bundle lock --update --bundler` (forcing Bundler to go through dependency resolution) ``` ==> memprof.after.txt <== Total allocated: 2.98 MB (48307 objects) Total retained: 1.21 MB (16507 objects) ==> memprof.before.txt <== Total allocated: 12.62 MB (198506 objects) Total retained: 1.30 MB (23133 objects) ``` 2) for `bin/rails runner true` (essentially only bundler/setup) ``` ==> memprof.after.txt <== Total allocated: 59.50 kB (1017 objects) Total retained: 25.08 kB (362 objects) ==> memprof.before.txt <== Total allocated: 561.82 kB (8575 objects) Total retained: 27.28 kB (513 objects) ``` https://github.com/rubygems/rubygems/commit/35c8ed2cb8
This commit is contained in:
parent
5810304c2e
commit
bf71b0eda5
@ -311,8 +311,8 @@ module Gem::QueryUtils
|
|||||||
label = "Installed at"
|
label = "Installed at"
|
||||||
specs.each do |s|
|
specs.each do |s|
|
||||||
version = s.version.to_s
|
version = s.version.to_s
|
||||||
version << ", default" if s.default_gem?
|
default = ", default" if s.default_gem?
|
||||||
entry << "\n" << " #{label} (#{version}): #{s.base_dir}"
|
entry << "\n" << " #{label} (#{version}#{default}): #{s.base_dir}"
|
||||||
label = " " * label.length
|
label = " " * label.length
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -162,7 +162,7 @@ class Gem::Version
|
|||||||
# A string representation of this Version.
|
# A string representation of this Version.
|
||||||
|
|
||||||
def version
|
def version
|
||||||
@version.dup
|
@version
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :to_s, :version
|
alias_method :to_s, :version
|
||||||
@ -173,7 +173,7 @@ class Gem::Version
|
|||||||
def self.correct?(version)
|
def self.correct?(version)
|
||||||
nil_versions_are_discouraged! if version.nil?
|
nil_versions_are_discouraged! if version.nil?
|
||||||
|
|
||||||
!!(version.to_s =~ ANCHORED_VERSION_PATTERN)
|
ANCHORED_VERSION_PATTERN.match?(version.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
@ -224,9 +224,17 @@ class Gem::Version
|
|||||||
end
|
end
|
||||||
|
|
||||||
# If version is an empty string convert it to 0
|
# If version is an empty string convert it to 0
|
||||||
version = 0 if version.is_a?(String) && version =~ /\A\s*\Z/
|
version = 0 if version.is_a?(String) && /\A\s*\Z/.match?(version)
|
||||||
|
|
||||||
@version = version.to_s.strip.gsub("-",".pre.")
|
@version = version.to_s
|
||||||
|
|
||||||
|
# optimization to avoid allocation when given an integer, since we know
|
||||||
|
# it's to_s won't have any spaces or dashes
|
||||||
|
unless version.is_a?(Integer)
|
||||||
|
@version = @version.strip
|
||||||
|
@version.gsub!("-",".pre.")
|
||||||
|
end
|
||||||
|
@version = -@version
|
||||||
@segments = nil
|
@segments = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -252,7 +260,7 @@ class Gem::Version
|
|||||||
# same precision. Version "1.0" is not the same as version "1".
|
# same precision. Version "1.0" is not the same as version "1".
|
||||||
|
|
||||||
def eql?(other)
|
def eql?(other)
|
||||||
self.class === other && @version == other._version
|
self.class === other && @version == other.version
|
||||||
end
|
end
|
||||||
|
|
||||||
def hash # :nodoc:
|
def hash # :nodoc:
|
||||||
@ -284,7 +292,7 @@ class Gem::Version
|
|||||||
end
|
end
|
||||||
|
|
||||||
def yaml_initialize(tag, map) # :nodoc:
|
def yaml_initialize(tag, map) # :nodoc:
|
||||||
@version = map["version"]
|
@version = -map["version"]
|
||||||
@segments = nil
|
@segments = nil
|
||||||
@hash = nil
|
@hash = nil
|
||||||
end
|
end
|
||||||
@ -302,7 +310,7 @@ class Gem::Version
|
|||||||
|
|
||||||
def prerelease?
|
def prerelease?
|
||||||
unless instance_variable_defined? :@prerelease
|
unless instance_variable_defined? :@prerelease
|
||||||
@prerelease = !(@version =~ /[a-zA-Z]/).nil?
|
@prerelease = /[a-zA-Z]/.match?(version)
|
||||||
end
|
end
|
||||||
@prerelease
|
@prerelease
|
||||||
end
|
end
|
||||||
@ -354,7 +362,7 @@ class Gem::Version
|
|||||||
return self <=> self.class.new(other) if (String === other) && self.class.correct?(other)
|
return self <=> self.class.new(other) if (String === other) && self.class.correct?(other)
|
||||||
|
|
||||||
return unless Gem::Version === other
|
return unless Gem::Version === other
|
||||||
return 0 if @version == other._version || canonical_segments == other.canonical_segments
|
return 0 if @version == other.version || canonical_segments == other.canonical_segments
|
||||||
|
|
||||||
lhsegments = canonical_segments
|
lhsegments = canonical_segments
|
||||||
rhsegments = other.canonical_segments
|
rhsegments = other.canonical_segments
|
||||||
@ -381,10 +389,26 @@ class Gem::Version
|
|||||||
end
|
end
|
||||||
|
|
||||||
def canonical_segments
|
def canonical_segments
|
||||||
@canonical_segments ||=
|
@canonical_segments ||= begin
|
||||||
_split_segments.map! do |segments|
|
numeric_segments, string_segments = _split_segments
|
||||||
segments.reverse_each.drop_while {|s| s == 0 }.reverse
|
canonical_segments = []
|
||||||
end.reduce(&:concat)
|
|
||||||
|
seen_non_zero = false
|
||||||
|
string_segments.reverse_each do |segment|
|
||||||
|
if seen_non_zero || (seen_non_zero = (segment != 0))
|
||||||
|
canonical_segments << segment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
seen_non_zero = false
|
||||||
|
numeric_segments.reverse_each do |segment|
|
||||||
|
if seen_non_zero || (seen_non_zero = (segment != 0))
|
||||||
|
canonical_segments << segment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
canonical_segments.reverse!
|
||||||
|
canonical_segments.freeze
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def freeze
|
def freeze
|
||||||
@ -395,17 +419,13 @@ class Gem::Version
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def _version
|
|
||||||
@version
|
|
||||||
end
|
|
||||||
|
|
||||||
def _segments
|
def _segments
|
||||||
# segments is lazy so it can pick up version values that come from
|
# segments is lazy so it can pick up version values that come from
|
||||||
# old marshaled versions, which don't go through marshal_load.
|
# old marshaled versions, which don't go through marshal_load.
|
||||||
# since this version object is cached in @@all, its @segments should be frozen
|
# since this version object is cached in @@all, its @segments should be frozen
|
||||||
|
|
||||||
@segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
|
@segments ||= @version.scan(/[0-9]+|[a-z]+/i).map! do |s|
|
||||||
/^\d+$/.match?(s) ? s.to_i : s
|
/^\d+$/.match?(s) ? s.to_i : -s
|
||||||
end.freeze
|
end.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user