Skip to content

Instantly share code, notes, and snippets.

@technicalpickles
Last active September 11, 2023 21:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save technicalpickles/91933d34dcd47bfc99d6ac0e53fcdb1e to your computer and use it in GitHub Desktop.
Save technicalpickles/91933d34dcd47bfc99d6ac0e53fcdb1e to your computer and use it in GitHub Desktop.
Bundler::Settings#[] benchmark, see https://github.com/rubygems/rubygems/pull/6923
require "benchmark/ips"
require "benchmark/memory"
require 'bundler'
class Bundler::Settings
def original(name)
key = key_for(name)
value = configs.values.map {|config| config[key] }.compact.first
converted_value(value, name)
end
def bang_method(name)
key = key_for(name)
values = configs.values
values.map! {|config| config[key] }
values.compact!
value = values.first
converted_value(value, name)
end
def with_detect(name)
key = key_for(name)
config_with_key = configs.values.detect {|config| config[key] }
value = config_with_key[key] if config_with_key
converted_value(value, name)
end
def with_detect_with_memoized_configs(name)
key = key_for(name)
config_with_key = configs.values.detect {|config| config[key] }
value = config_with_key[key] if config_with_key
converted_value(value, name)
end
def manual_loop(name)
key = key_for(name)
value = nil
configs.each do |_, config|
if config[key]
value = config[key]
break
end
end
converted_value(value, name)
end
def manual_loop_with_memoized_configs(name)
key = key_for(name)
value = nil
memoized_configs.each do |_, config|
if config[key]
value = config[key]
break
end
end
converted_value(value, name)
end
def correct_manual_loop(name)
key = key_for(name)
value = nil
configs.each do |_, config|
value = config[key]
next if value.nil?
break
end
converted_value(value, name)
end
def correct_manual_loop_with_memoized_configs(name)
key = key_for(name)
value = nil
memoized_configs.each do |_, config|
value = config[key]
next if value.nil?
break
end
converted_value(value, name)
end
def correct_manual_with_each_config(name)
key = key_for(name)
value = nil
each_config do |config|
value = config[key]
next if value.nil?
break
end
converted_value(value, name)
end
def with_flat_map(name)
key = key_for(name)
value = configs.flat_map {|_, config| break config[key] unless config[key].nil? }
converted_value(value, name)
end
private
def each_config
yield @temporary
yield @local_config
yield @env_config
yield @global_config
yield DEFAULT_CONFIG
end
def memoized_configs
@memoized_configs ||= {
:temporary => @temporary,
:local => @local_config,
:env => @env_config,
:global => @global_config,
:default => DEFAULT_CONFIG,
}.freeze
end
end
# warm up memoization
Bundler.settings.manual_loop_with_memoized_configs(:silence_deprecations)
Benchmark.memory do |x|
x.report("original") { Bundler.settings.original(:force_ruby_platform) }
x.report("bang_method") { Bundler.settings.bang_method(:force_ruby_platform) }
x.report("with_detect") { Bundler.settings.with_detect(:force_ruby_platform) }
x.report("with_detect w/ memoized configs") { Bundler.settings.with_detect_with_memoized_configs(:force_ruby_platform) }
x.report("manual_loop") { Bundler.settings.manual_loop(:force_ruby_platform) }
x.report("manual_loop w/ memoized configs") { Bundler.settings.manual_loop_with_memoized_configs(:force_ruby_platform) }
x.report("correct manual_loop") { Bundler.settings.correct_manual_loop(:force_ruby_platform) }
x.report("correct manual_loop w/ memoized configs") { Bundler.settings.correct_manual_loop_with_memoized_configs(:force_ruby_platform) }
x.report("correct manual_loop w/ each_config") { Bundler.settings.correct_manual_with_each_config(:force_ruby_platform) }
x.report("with_flat_map") { Bundler.settings.with_flat_map(:force_ruby_platform) }
x.compare!
end
Benchmark.ips do |x|
x.report("original") { Bundler.settings.original(:force_ruby_platform) }
x.report("bang_method") { Bundler.settings.bang_method(:force_ruby_platform) }
x.report("with_detect") { Bundler.settings.with_detect(:force_ruby_platform) }
x.report("with_detect w/ memoized configs") { Bundler.settings.with_detect_with_memoized_configs(:force_ruby_platform) }
x.report("manual_loop") { Bundler.settings.manual_loop(:force_ruby_platform) }
x.report("manual_loop w/ memoized configs") { Bundler.settings.manual_loop_with_memoized_configs(:force_ruby_platform) }
x.report("correct manual_loop") { Bundler.settings.correct_manual_loop(:force_ruby_platform) }
x.report("correct manual_loop w/ memoized configs") { Bundler.settings.correct_manual_loop_with_memoized_configs(:force_ruby_platform) }
x.report("correct manual_loop w/ each_config") { Bundler.settings.correct_manual_with_each_config(:force_ruby_platform) }
x.report("with_flat_map") { Bundler.settings.with_flat_map(:force_ruby_platform) }
x.compare! order: :baseline
end
Calculating -------------------------------------
original 720.000 memsize ( 0.000 retained)
10.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
bang_method 560.000 memsize ( 0.000 retained)
8.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
with_detect 560.000 memsize ( 80.000 retained)
8.000 objects ( 1.000 retained)
3.000 strings ( 0.000 retained)
with_detect w/ memoized configs
560.000 memsize ( 0.000 retained)
8.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
manual_loop 480.000 memsize ( 0.000 retained)
7.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
manual_loop w/ memoized configs
312.000 memsize ( 72.000 retained)
6.000 objects ( 1.000 retained)
3.000 strings ( 1.000 retained)
correct manual_loop 480.000 memsize ( 0.000 retained)
7.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
correct manual_loop w/ memoized configs
312.000 memsize ( 72.000 retained)
6.000 objects ( 1.000 retained)
3.000 strings ( 1.000 retained)
correct manual_loop w/ each_config
312.000 memsize ( 0.000 retained)
6.000 objects ( 0.000 retained)
3.000 strings ( 0.000 retained)
with_flat_map 920.000 memsize ( 168.000 retained)
14.000 objects ( 1.000 retained)
3.000 strings ( 0.000 retained)
Comparison:
correct manual_loop w/ memoized configs: 312 allocated
manual_loop w/ memoized configs: 312 allocated - same
correct manual_loop w/ each_config: 312 allocated - same
correct manual_loop: 480 allocated - 1.54x more
manual_loop: 480 allocated - 1.54x more
with_detect: 560 allocated - 1.79x more
with_detect w/ memoized configs: 560 allocated - 1.79x more
bang_method: 560 allocated - 1.79x more
original: 720 allocated - 2.31x more
with_flat_map: 920 allocated - 2.95x more
Warming up --------------------------------------
original 90.970k i/100ms
bang_method 90.281k i/100ms
with_detect 85.338k i/100ms
with_detect w/ memoized configs
89.005k i/100ms
manual_loop 92.693k i/100ms
manual_loop w/ memoized configs
103.907k i/100ms
correct manual_loop 88.976k i/100ms
correct manual_loop w/ memoized configs
100.113k i/100ms
correct manual_loop w/ each_config
112.645k i/100ms
with_flat_map 52.569k i/100ms
Calculating -------------------------------------
original 900.679k (± 2.7%) i/s - 4.548M in 5.054191s
bang_method 921.335k (± 5.2%) i/s - 4.604M in 5.017818s
with_detect 874.357k (± 1.2%) i/s - 4.438M in 5.075983s
with_detect w/ memoized configs
874.308k (± 1.0%) i/s - 4.450M in 5.090577s
manual_loop 923.377k (± 0.9%) i/s - 4.635M in 5.019649s
manual_loop w/ memoized configs
1.042M (± 1.5%) i/s - 5.299M in 5.087562s
correct manual_loop 892.766k (± 1.2%) i/s - 4.538M in 5.083618s
correct manual_loop w/ memoized configs
1.023M (± 0.7%) i/s - 5.206M in 5.086753s
correct manual_loop w/ each_config
1.136M (± 0.7%) i/s - 5.745M in 5.058002s
with_flat_map 540.224k (± 0.7%) i/s - 2.734M in 5.060378s
Comparison:
original: 900679.3 i/s
correct manual_loop w/ each_config: 1135861.2 i/s - 1.26x faster
manual_loop w/ memoized configs: 1041836.7 i/s - 1.16x faster
correct manual_loop w/ memoized configs: 1023470.5 i/s - 1.14x faster
manual_loop: 923377.4 i/s - same-ish: difference falls within error
bang_method: 921335.0 i/s - same-ish: difference falls within error
correct manual_loop: 892766.1 i/s - same-ish: difference falls within error
with_detect: 874357.4 i/s - same-ish: difference falls within error
with_detect w/ memoized configs: 874308.3 i/s - same-ish: difference falls within error
with_flat_map: 540224.1 i/s - 1.67x slower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment