[pull] master from ruby:master#869
Merged
pull[bot] merged 113 commits intoturkdevops:masterfrom Mar 20, 2026
Merged
Conversation
…t_append, and pm_string_owned_init ruby/prism@a52c48186e
Prism changed structure quite a bit. Most of the previously-public structs are now opaque. This requires quite a bit of changes internally. It also triggered some unrelated changes, which were necessary because Prism's main header used to pull in standard headers. So box.c and jit.c are now no longer transitively getting all the headers they needed.
The method for marking something as deprecated is currently unused but seems fine leave as is. ruby/prism@5b523dfe6e
- ### Problem
Comparing Gem::Version objects is slow. It's particularly a problem
because `Gem::Version#<=>` is called million of times during
resolution when using a real world Gemfile in a large application.
The comparison has to compare all segments between the two objects,
enter conditional branches and check lexicographical order when
version is a prerelease.
### Solution
I'd like to provide a fast path for the simple scenarios by turning
a version into an integer.
By "simple scenario" I mean version up to 4 segments which
represents the vast majority of the version scheme released by
maintainers.
For sake of simplicity and understability of the code I opted to not
include prelease version ("1.0.0.alpha") in the fast path.
We'd need to turn the "pre" string into a integer while keeping
lexicographical order (`1.0.0.beta` > `1.0.0.alpha`) and I felt
it wasn't worth the complexity.
Overall, this change makes comparing version up to 5x faster (when
one version is higher than the other)
There is no speed gain when 2 versions are the same as there is
already a fast path implemented.
Checking prerelease version is a bit slower now due to a `nil` check
we are doing.
### Benchmarks
```ruby
require "benchmark/ips"
a = Gem::Version.new("5.3.1")
b = Gem::Version.new("5.3.2")
c = Gem::Version.new("5.3.1")
d = Gem::Version.new("2.0.0.alpha")
Benchmark.ips do |x|
x.report("less than regular:") { a <=> b }
x.report("less than optimized:") { a <=> b }
x.hold!("lesser_than_temp_results")
x.compare!(order: :baseline)
end
Benchmark.ips do |x|
x.report("greater than regular:") { b <=> a }
x.report("greater than optimized:") { b <=> a }
x.hold!("greater_than_temp_results")
x.compare!(order: :baseline)
end
Benchmark.ips do |x|
x.report("equal regular:") { a <=> c }
x.report("equal optimized:") { a <=> c }
x.hold!("equal_temp_results")
x.compare!(order: :baseline)
end
Benchmark.ips do |x|
x.report("prerelase regular:") { a <=> d }
x.report("prerelease optimized:") { a <=> d }
x.hold!("prerelease_temp_results")
x.compare!(order: :baseline)
end
```
```
Warming up --------------------------------------
less than optimized: 1.352M i/100ms
Calculating -------------------------------------
less than optimized: 13.599M (± 0.8%) i/s (73.53 ns/i) - 68.947M in 5.070279s
Comparison:
less than regular:: 2622912.7 i/s
less than optimized:: 13599139.2 i/s - 5.18x faster
_________________________
Warming up --------------------------------------
greater than optimized:
1.355M i/100ms
Calculating -------------------------------------
greater than optimized:
13.581M (± 0.6%) i/s (73.63 ns/i) - 69.120M in 5.089497s
Comparison:
greater than regular:: 2637899.0 i/s
greater than optimized:: 13581319.7 i/s - 5.15x faster
_________________________
Warming up --------------------------------------
equal optimized: 1.360M i/100ms
Calculating -------------------------------------
equal optimized: 13.577M (± 0.7%) i/s (73.65 ns/i) - 68.010M in 5.009445s
Comparison:
equal regular:: 13885209.5 i/s
equal optimized:: 13576932.0 i/s - same-ish: difference falls within error
_________________________
Warming up --------------------------------------
prerelease optimized:
358.680k i/100ms
Calculating -------------------------------------
prerelease optimized:
3.595M (± 0.6%) i/s (278.17 ns/i) - 18.293M in 5.088687s
Comparison:
prerelase regular:: 4174692.2 i/s
prerelease optimized:: 3594907.8 i/s - 1.16x slower
```
ruby/rubygems@6ef9f279d9
The 4.0.0 version break CI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )