Skip to content

Instantly share code, notes, and snippets.

@apauly
Last active January 9, 2020 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apauly/3f547f06e83b66e4187e48519b426464 to your computer and use it in GitHub Desktop.
Save apauly/3f547f06e83b66e4187e48519b426464 to your computer and use it in GitHub Desktop.
Benchmark for fix in ActiveSupport
require 'json'
require 'active_support/all'
#
# Monkeypatch Hash class in order to be able to compare both version
#
class Hash
def as_json(options = nil) #:nodoc:
# create a subset of the hash by applying :only or :except
subset = if options
if attrs = options[:only]
slice(*Array(attrs))
elsif attrs = options[:except]
except(*Array(attrs))
else
self
end
else
self
end
if $patched
# updated version
result = {}
subset.each do |k, v|
result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
end
result
else
# previous version
Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
end
end
end
# Actual benchmark code
def build_random_hash(number, nesting=0)
return number if nesting == 0
number.times.map{|i|
[i, build_random_hash(number, nesting - 1)]
}.to_h
end
def compare(hash)
GC.start
$patched = true
allocated_before = GC.stat(:total_allocated_objects)
hash.as_json
allocated_after = GC.stat(:total_allocated_objects)
patched = "Object count after patch: #{allocated_after - allocated_before}"
GC.start
$patched = false
allocated_before = GC.stat(:total_allocated_objects)
hash.as_json
allocated_after = GC.stat(:total_allocated_objects)
not_patched = "Object count before patch: #{allocated_after - allocated_before}"
puts patched
puts not_patched
end
compare build_random_hash(1, 1)
compare build_random_hash(1, 10)
compare build_random_hash(3, 3)
compare build_random_hash(5, 5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment