tapioca
tapioca copied to clipboard
Optimize `URLHelpers.gather_constants`
trafficstars
Motivation
Profiling tapioca DSL SomeConst identified this method as a hot spot, taking roughly 1 out of the 6 total second spent by Tapioca (not including application load time).
The changes in this PR speed it up by ~500-800ms, but I need to remeasure to confirm.
toy micro-benchmarks
#!/usr/bin/ruby
#require "awesome_print"
#require "active_support/all"
require "benchmark/ips"
module HelloWorld
def hello_world!
puts "Hello, word!"
end
end
class GrandParent; end
class Parent < GrandParent; end
class Child < Parent
include HelloWorld
end
module Unrelated; end
def ancestors_of(mod) = mod.ancestors
def superclass_of(cls) = cls.superclass
def includes_helper?(mod, helper)
superclass_ancestors = []
if Class === mod
superclass = superclass_of(mod)
superclass_ancestors = ancestors_of(superclass) if superclass
end
ancestors = Set.new.compare_by_identity.merge(ancestors_of(mod)).subtract(superclass_ancestors)
ancestors.any? { |ancestor| helper == ancestor }
end
def includes_helper_2?(mod, helper)
if Class === mod
superclass = superclass_of(mod)
ancestors_of(mod).take_while { |a| !superclass.equal?(a) }.include?(helper)
else
ancestors_of(mod).include?(helper)
end
end
def includes_helper_3?(mod, helper)
return ancestors_of(mod).include?(helper) unless Class === mod
superclass = superclass_of(mod)
ancestors_of(mod).each do |a|
return true if helper.equal?(a)
return false if superclass.equal?(a)
end
false
end
def direct_ancestors_of(mod)
if Class === mod
superclass = superclass_of(mod)
ancestors_of(mod).take_while { |a| !superclass.equal?(a) }
else
ancestors_of(mod)
end
end
Benchmark.ips do |x|
x.config(warmup: 1, time: 5)
x.report("original") do |times|
i = 0
while (i += 1) < times
includes_helper?(Child, HelloWorld)
includes_helper?(Child, Unrelated)
end
end
x.report("variant 2") do |times|
i = 0
while (i += 1) < times
includes_helper_2?(Child, HelloWorld)
includes_helper_2?(Child, Unrelated)
end
end
x.report("variant 3") do |times|
i = 0
while (i += 1) < times
includes_helper_3?(Child, HelloWorld)
includes_helper_3?(Child, Unrelated)
end
end
x.report("direct_ancestors_of") do |times|
i = 0
while (i += 1) < times
direct_ancestors = direct_ancestors_of(Child)
direct_ancestors.include?(HelloWorld)
direct_ancestors.include?(Unrelated)
end
end
x.compare!
end