1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

Rewrite old attribute mapping to save many object allocations

Stringifying the keys of a hash can be done without allocating many
arrays like the previous approach did.

```ruby
begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update
                your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  gem "benchmark-ips"
end

def allocate_count
  GC.disable
  before = ObjectSpace.count_objects
  yield
  after = ObjectSpace.count_objects
  after.each { |k,v| after[k] = v - before[k] }
  after[:T_HASH] -= 1 # probe effect - we created the before hash.
  GC.enable
  result = after.reject { |k,v| v == 0 }
  GC.start
  result
end

@old = {a: :b, c: :d, e: :f}

def master_version
  Hash[@old.map { |k, v| [k.to_s, v] }]
end

def fast_version
  result = {}
  @old.each { |k, v| result[k.to_s] = v }
end

puts "master_version"
puts allocate_count { 1000.times { master_version } }
puts "fast_version"
puts allocate_count { 1000.times { fast_version } }

Benchmark.ips do |x|
  x.report("master_version") { master_version }
  x.report("fast_version")     { fast_version }
  x.compare!
end
```

```ruby
master_version
{:FREE=>-14768, :T_STRING=>6054, :T_ARRAY=>7000, :T_HASH=>1000, :T_IMEMO=>1000}
fast_version
{:FREE=>-7001, :T_STRING=>6000, :T_HASH=>1000}
Warming up --------------------------------------
      master_version    38.137k i/100ms
        fast_version    50.133k i/100ms
Calculating -------------------------------------
      master_version    451.898k (±19.2%) i/s -      2.174M in   5.002186s
        fast_version    633.579k (±19.4%) i/s -      3.058M in   5.019391s

Comparison:
        fast_version:   633578.7 i/s
      master_version:   451897.6 i/s - same-ish: difference falls within error
```
This commit is contained in:
Dillon Welch 2017-10-23 17:34:53 -07:00
parent b41322ec77
commit 1043a6d866

View file

@ -132,7 +132,9 @@ module Haml
def attributes(class_id, obj_ref, *attributes_hashes)
attributes = class_id
attributes_hashes.each do |old|
AttributeBuilder.merge_attributes!(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
result = {}
old.each { |k, v| result[k.to_s] = v }
AttributeBuilder.merge_attributes!(attributes, result)
end
AttributeBuilder.merge_attributes!(attributes, parse_object_ref(obj_ref)) if obj_ref
AttributeBuilder.build_attributes(