[ruby-core:94507] [Ruby master Feature#16121] Stop making a redundant hash copy in Hash#dup
From:
dylan.smith@...
Date:
2019-08-23 17:11:08 UTC
List:
ruby-core #94507
Issue #16121 has been reported by dylants (Dylan Thacker-Smith).
----------------------------------------
Feature #16121: Stop making a redundant hash copy in Hash#dup
https://bugs.ruby-lang.org/issues/16121
* Author: dylants (Dylan Thacker-Smith)
* Status: Open
* Priority: Normal
* Assignee:
* Target version:
----------------------------------------
## Problem
I noticed while profiling object allocations that Hash#dup was allocating 2 objects instead of only 1 as expected. I looked for alternatives for comparison and found that `Hash[hash]` created a copy with only a single object allocation and seemed to be more than twice as fast. Reading the source code revealed the difference was that Hash#dup creates a copy of the Hash, then rehashes the copy. However, rehashing is done by making a copy of the hash, so the first copy before rehashing was unnecessary.
## Solution
I changed the code to just use rehashing to make the copy of the hash to improve performance while also preserving the existing behaviour.
## Benchmark
```ruby
require 'benchmark'
N = 100000
def report(x, name)
x.report(name) do
N.times do
yield
end
end
end
hashes = {
small_hash: { a: 1 },
larger_hash: 20.times.map { |i| [('a'.ord + i).chr.to_sym, i] }.to_h
}
Benchmark.bmbm do |x|
hashes.each do |name, hash|
report(x, "#{name}.dup") do
hash.dup
end
end
end
```
results on master
```
user system total real
small_hash.dup 0.401350 0.001638 0.402988 ( 0.404608)
larger_hash.dup 7.218548 0.433616 7.652164 ( 7.695990)
```
results with the attached patch
```
user system total real
small_hash.dup 0.336733 0.002425 0.339158 ( 0.341760)
larger_hash.dup 6.617343 0.398407 7.015750 ( 7.070282)
```
---Files--------------------------------
0001-Stop-making-a-redundant-hash-copy-in-Hash-dup.diff.txt (1.93 KB)
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>