only loop over spec dependencies to resolve conflicts #842

Merged
merged 1 commit into from Mar 13, 2014

Conversation

Projects
None yet
2 participants
Contributor

tenderlove commented Mar 5, 2014

Before this commit, the conflicts method would loop over every
activated gem and the conflicts method would get slower as you
activate more gems.

This commit speeds up the conflicts method which is called on ever gem
activation by only looping over dependencies on the spec itself, then
looking up possible conflicts from the loaded_specs hash.

Here is the benchmark:

def util_spec name, version = 2
  spec = Gem::Specification.new do |s|
    s.platform    = Gem::Platform::RUBY
    s.name        = name
    s.version     = version
    s.author      = 'A User'
    s.email       = 'example@example.com'
    s.homepage    = 'http://example.com'
    s.summary     = "this is a summary"
    s.description = "This is a test description"
  end

  spec.loaded_from = spec.spec_file

  Gem::Specification.add_spec spec

  return spec
end

require 'benchmark/ips'

(ENV['N'] || 100).to_i.times { |i| util_spec(i.to_s).activate }

p Gem.loaded_specs.size

Benchmark.ips do |x|
  spec = util_spec 'a'
  # Typical mode, runs the block as many times as it can
  x.report("conflicts") { spec.conflicts }
end

Before my change:

[aaron@higgins rubygems (master)]$ N=100 ruby -I lib test.rb
101
Calculating -------------------------------------
           conflicts      1957 i/100ms
-------------------------------------------------
           conflicts    20090.1 (±4.6%) i/s -     101764 in   5.077002s
[aaron@higgins rubygems (master)]$ N=1000 ruby -I lib test.rb
1001
Calculating -------------------------------------
           conflicts       214 i/100ms
-------------------------------------------------
           conflicts     2209.6 (±5.0%) i/s -      11128 in   5.050977s

After my change:

[aaron@higgins rubygems (master)]$ N=100 ruby -I lib test.rb
101
Calculating -------------------------------------
           conflicts     71357 i/100ms
-------------------------------------------------
           conflicts  2230414.4 (±7.2%) i/s -   11131692 in   5.022458s
[aaron@higgins rubygems (master)]$ N=1000 ruby -I lib test.rb
1001
Calculating -------------------------------------
           conflicts     69479 i/100ms
-------------------------------------------------
           conflicts  2171237.1 (±6.2%) i/s -   10838724 in   5.013410s

You can see that after this change the speed of conflicts stays about
the same regardless of the number of specs loaded.

@tenderlove tenderlove only loop over spec dependencies to resolve conflicts
Before this commit, the `conflicts` method would loop over every
activated gem and the `conflicts` method would get slower as you
activate more gems.

This commit speeds up the `conflicts` method which is called on ever gem
activation by only looping over dependencies on the spec itself, then
looking up possible conflicts from the loaded_specs hash.

Here is the benchmark:

```ruby
def util_spec name, version = 2
  spec = Gem::Specification.new do |s|
    s.platform    = Gem::Platform::RUBY
    s.name        = name
    s.version     = version
    s.author      = 'A User'
    s.email       = 'example@example.com'
    s.homepage    = 'http://example.com'
    s.summary     = "this is a summary"
    s.description = "This is a test description"
  end

  spec.loaded_from = spec.spec_file

  Gem::Specification.add_spec spec

  return spec
end

require 'benchmark/ips'

(ENV['N'] || 100).to_i.times { |i| util_spec(i.to_s).activate }

p Gem.loaded_specs.size

Benchmark.ips do |x|
  spec = util_spec 'a'
  # Typical mode, runs the block as many times as it can
  x.report("conflicts") { spec.conflicts }
end
```

Before my change:

```
[aaron@higgins rubygems (master)]$ N=100 ruby -I lib test.rb
101
Calculating -------------------------------------
           conflicts      1957 i/100ms
-------------------------------------------------
           conflicts    20090.1 (±4.6%) i/s -     101764 in   5.077002s
[aaron@higgins rubygems (master)]$ N=1000 ruby -I lib test.rb
1001
Calculating -------------------------------------
           conflicts       214 i/100ms
-------------------------------------------------
           conflicts     2209.6 (±5.0%) i/s -      11128 in   5.050977s
```

After my change:

```
[aaron@higgins rubygems (master)]$ N=100 ruby -I lib test.rb
101
Calculating -------------------------------------
           conflicts     71357 i/100ms
-------------------------------------------------
           conflicts  2230414.4 (±7.2%) i/s -   11131692 in   5.022458s
[aaron@higgins rubygems (master)]$ N=1000 ruby -I lib test.rb
1001
Calculating -------------------------------------
           conflicts     69479 i/100ms
-------------------------------------------------
           conflicts  2171237.1 (±6.2%) i/s -   10838724 in   5.013410s
```

You can see that after this change the speed of `conflicts` stays about
the same regardless of the number of specs loaded.
3e6cd47

@zenspider zenspider added a commit that referenced this pull request Mar 13, 2014

@zenspider zenspider Merge pull request #842 from tenderlove/perf
only loop over spec dependencies to resolve conflicts
f3774bb

@zenspider zenspider merged commit f3774bb into rubygems:master Mar 13, 2014

1 check passed

default The Travis CI build passed
Details

@drbrain drbrain added a commit that referenced this pull request Mar 14, 2014

@drbrain drbrain Add #842 to History e2e3235

@zzak zzak added a commit to zzak/rubygems that referenced this pull request May 9, 2014

@drbrain @zzak drbrain + zzak Add #842 to History 297f38c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment