Skip to content

Instantly share code, notes, and snippets.

@ridiculous
Last active December 11, 2015 02:08
Show Gist options
  • Save ridiculous/be52492aea3c17352241 to your computer and use it in GitHub Desktop.
Save ridiculous/be52492aea3c17352241 to your computer and use it in GitHub Desktop.
Looks for a correlation between method call time and # classes in the object space
require 'benchmark'
class ScratchNGo
#= Class Description
# Looks for a correlation between method call time and # classes in the object space. We do this by creating an initial
# sample size of new classes, each defined with the same number of methods. We then benchmark the call time for all methods of the
# original sample size of classes. We then create additional sets of class samples, measuring the call time of the original
# set each time.
def initialize(args)
@class_size = (args.pop || 5_000).to_i
@method_size = 20
end
def run
puts "Running benchmarks for #{@class_size} classes each with #{@method_size} methods"
Benchmark.benchmark do |metrics|
metrics.report("+ #{@class_size} classes") { create_classes 'call' }
metrics.report("Calling methods ...") { call_methods }
metrics.report("+ #{@class_size} classes") { create_classes 'true' }
metrics.report("Calling methods ...") { call_methods }
metrics.report("+ #{@class_size} classes") { create_classes 'false' }
metrics.report("Calling methods ...") { call_methods }
metrics.report("+ #{@class_size} classes") { create_classes 'nil' }
metrics.report("Calling methods ...") { call_methods }
metrics.report("+ #{@class_size} classes") { create_classes 'class' }
metrics.report("Calling methods ...") { call_methods }
metrics.report("+ #{@class_size} classes") { create_classes 'module' }
metrics.report("Calling methods ...") { call_methods }
end
end
def call_methods(name_prefix = 'call')
@classes ||= classes.select { |klass| klass.respond_to?("#{name_prefix}_0") }
@classes.each do |klass|
methods = klass.public_methods - Object.methods
methods.each do |method_name|
klass.allocate.send(method_name)
end
end
end
def create_classes(name_prefix)
@class_size.times do
klass_name = generate_class_name
klass = Class.new(Object)
@method_size.times do |i|
klass.send :define_method, "#{name_prefix}_#{i}", ->() {}
klass.define_singleton_method "#{name_prefix}_#{i}", ->() {}
end
Object.const_set klass_name, klass
end
end
def generate_class_name
words.sample(2).map(&:capitalize).join.gsub /\W/, ''
end
def classes
ObjectSpace.each_object(Class).lazy
end
def words
@words ||= File.readlines('/usr/share/dict/words').map(&:chomp)
end
end
ScratchNGo.new(ARGV).run
# $ ruby scratch_n_go.rb
# Running benchmarks for 5000 classes each with 20 methods
# + 5000 classes 0.990000 0.060000 1.050000 ( 1.176519)
# Calling methods ... 0.920000 0.000000 0.920000 ( 0.926232)
# + 5000 classes 0.770000 0.040000 0.810000 ( 0.796057)
# Calling methods ... 0.910000 0.000000 0.910000 ( 0.924063)
# + 5000 classes 1.100000 0.040000 1.140000 ( 1.125203)
# Calling methods ... 0.930000 0.000000 0.930000 ( 0.940422)
# + 5000 classes 0.930000 0.040000 0.970000 ( 0.969951)
# Calling methods ... 1.480000 0.010000 1.490000 ( 1.487894)
# + 5000 classes 0.720000 0.080000 0.800000 ( 0.805329)
# Calling methods ... 1.220000 0.000000 1.220000 ( 1.215931)
# + 5000 classes 1.560000 0.030000 1.590000 ( 1.598290)
# Calling methods ... 1.230000 0.010000 1.240000 ( 1.234221)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment