benchmarks/module_inclusion_filtering.rb
require_relative "../bundle/bundler/setup" # configures load paths
require 'rspec/core'
class << RSpec
attr_writer :world
end
# Here we are restoring the old implementation of `configure_group`, so that
# we can toggle the new vs old implementation in the benchmark by aliasing it.
module RSpecConfigurationOverrides
def initialize(*args)
super
@include_extend_or_prepend_modules = []
end
def include(mod, *filters)
meta = RSpec::Core::Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
@include_extend_or_prepend_modules << [:include, mod, meta]
super
end
def old_configure_group(group)
@include_extend_or_prepend_modules.each do |include_extend_or_prepend, mod, filters|
next unless filters.empty? || RSpec::Core::MetadataFilter.apply?(:any?, filters, group.metadata)
__send__("safe_#{include_extend_or_prepend}", mod, group)
end
end
def self.prepare_implementation(prefix)
RSpec.world = RSpec::Core::World.new # clear our state
RSpec::Core::Configuration.class_eval do
alias_method :configure_group, :"#{prefix}_configure_group"
end
end
end
RSpec::Core::Configuration.class_eval do
prepend RSpecConfigurationOverrides
alias new_configure_group configure_group
end
RSpec.configure do |c|
50.times { c.include Module.new, :include_it }
end
require 'benchmark/ips'
Benchmark.ips do |x|
x.report("Old linear search: non-matching metadata") do |times|
RSpecConfigurationOverrides.prepare_implementation(:old)
times.times { |i| RSpec.describe "Old linear search: non-matching metadata #{i}" }
end
x.report("New memoized search: non-matching metadata") do |times|
RSpecConfigurationOverrides.prepare_implementation(:new)
times.times { |i| RSpec.describe "New memoized search: non-matching metadata #{i}" }
end
x.report("Old linear search: matching metadata") do |times|
RSpecConfigurationOverrides.prepare_implementation(:old)
times.times { |i| RSpec.describe "Old linear search: matching metadata #{i}", :include_it }
end
x.report("New memoized search: matching metadata") do |times|
RSpecConfigurationOverrides.prepare_implementation(:new)
times.times { |i| RSpec.describe "New memoized search: matching metadata #{i}", :include_it }
end
end
__END__
Calculating -------------------------------------
Old linear search: non-matching metadata
86.000 i/100ms
New memoized search: non-matching metadata
93.000 i/100ms
Old linear search: matching metadata
79.000 i/100ms
New memoized search: matching metadata
90.000 i/100ms
-------------------------------------------------
Old linear search: non-matching metadata
884.109 (±61.9%) i/s - 3.268k
New memoized search: non-matching metadata
1.099k (±81.2%) i/s - 3.441k
Old linear search: matching metadata
822.348 (±57.5%) i/s - 3.081k
New memoized search: matching metadata
1.116k (±76.6%) i/s - 3.510k