diff --git a/benchmark/each_bang_bm.rb b/benchmark/array_each_bang_bm.rb similarity index 99% rename from benchmark/each_bang_bm.rb rename to benchmark/array_each_bang_bm.rb index 3670529..f4d840e 100644 --- a/benchmark/each_bang_bm.rb +++ b/benchmark/array_each_bang_bm.rb @@ -13,7 +13,6 @@ class Thing; end puts '----------------------' arr = Array.new(100) { Thing.new } -line = '' arr.each do |el| GC.start diff --git a/benchmark/each_slice_bang_bm.rb b/benchmark/each_slice_bang_bm.rb index 154d78d..318c4cc 100644 --- a/benchmark/each_slice_bang_bm.rb +++ b/benchmark/each_slice_bang_bm.rb @@ -15,7 +15,6 @@ class Thing; end puts '----------------------' arr = Array.new(100) { Thing.new } -line = '' arr.each_slice(slize_size) do |slice| GC.start diff --git a/benchmark/hash_each_bang_bm.rb b/benchmark/hash_each_bang_bm.rb new file mode 100644 index 0000000..e6863d4 --- /dev/null +++ b/benchmark/hash_each_bang_bm.rb @@ -0,0 +1,104 @@ +require 'benchmark' +require_relative '../lib/hyper_iterator' + +class Key; end +class Val; end + +puts '---------------------------------------------------------' +puts '------------------------- each! -------------------------' + +puts '---------------------------------------------------------' +puts '------------------ Garbage Collection -------------------' + +puts 'Hash#each' +puts '----------------------' + +hash = {} +100.times do + hash[Key.new] = Val.new +end + +hash.each do |_| + GC.start + print ObjectSpace.each_object(Key).count + print ' ' + print ObjectSpace.each_object(Val).count + print ' ' +end + +puts +puts + +puts 'Hash#each!' +puts '----------------------' + +hash = {} +100.times do + hash[Key.new] = Val.new +end + +hash.each! do |_| + GC.start + print ObjectSpace.each_object(Key).count + print ' ' + print ObjectSpace.each_object(Val).count + print ' ' +end + +puts + +puts '---------------------------------------------------------' +puts '-------------------- Objects Created --------------------' + + +GC.disable +hash = {} +100.times do + hash[Key.new] = Val.new +end + +before = ObjectSpace.count_objects +hash.each do |_| +end +after = ObjectSpace.count_objects + +puts 'Hash#each' +puts '----------------------' +puts "# of arrays: %d" % (after[:T_ARRAY] - before[:T_ARRAY]) +puts "# of nodes: %d" % (after[:T_NODE] - before[:T_NODE]) + +puts + +hash = {} +100.times do + hash[Key.new] = Val.new +end + +before = ObjectSpace.count_objects +hash.each! do |el| +end +after = ObjectSpace.count_objects + +puts 'Hash#each!' +puts '----------------------' +puts "# of arrays: %d" % (after[:T_ARRAY] - before[:T_ARRAY]) +puts "# of nodes: %d" % (after[:T_NODE] - before[:T_NODE]) + +puts '---------------------------------------------------------' +puts '--------------- Execution Time Comparison ---------------' + +GC.enable +n = 10 +hash = {} +10_000.times do + hash[Key.new] = Val.new +end + +Benchmark.bmbm(7) do |x| + x.report('each!') { n.times { hash.each! { |el| nil } } } + x.report('each') { n.times { hash.each { |el| nil } } } +end + +puts '---------------------------------------------------------' + +puts \ No newline at end of file diff --git a/benchmark/memory_bm/each.rb b/benchmark/memory_bm/array_each.rb similarity index 100% rename from benchmark/memory_bm/each.rb rename to benchmark/memory_bm/array_each.rb diff --git a/benchmark/memory_bm/each_bang.rb b/benchmark/memory_bm/array_each_bang.rb similarity index 100% rename from benchmark/memory_bm/each_bang.rb rename to benchmark/memory_bm/array_each_bang.rb diff --git a/benchmark/memory_bm/hash_each.rb b/benchmark/memory_bm/hash_each.rb new file mode 100644 index 0000000..9a9b29d --- /dev/null +++ b/benchmark/memory_bm/hash_each.rb @@ -0,0 +1,34 @@ +require 'benchmark' +require_relative '../../lib/hyper_iterator' +$stdout.sync = true + +puts +puts '----------------- Hash#each -----------------' +puts '#i user system total real' + +base_hash = {} +1000.times { |i| base_hash["k#{i}"] = '-' * 10 } +hashes = [base_hash] + +i = 0 +while true + print "#{i} " + hash = {} + report = Benchmark.measure do + hashes[i].each do |k, v| + hash[k.dup] = v.dup + end + + # Try to use this line and see how many more iterations you can get + # Remember to uncomment line#24 as well. + # You need to pop the array so the reference goes away. + # arrs[0].each! { |el| arr << el.dup } + end + + # Uncomment this to use with the above line#22 + # arrs.pop + + puts report + hashes << hash + i += 1 +end diff --git a/benchmark/memory_bm/hash_each_bang.rb b/benchmark/memory_bm/hash_each_bang.rb new file mode 100644 index 0000000..1e6752c --- /dev/null +++ b/benchmark/memory_bm/hash_each_bang.rb @@ -0,0 +1,34 @@ +require 'benchmark' +require_relative '../../lib/hyper_iterator' +$stdout.sync = true + +puts +puts '----------------- Hash#each! -----------------' +puts '#i user system total real' + +base_hash = {} +1000.times { |i| base_hash["k#{i}"] = '-' * 10 } +hashes = [base_hash] + +i = 0 +while true + print "#{i} " + hash = {} + report = Benchmark.measure do + hashes[i].each! do |k, v| + hash[k.dup] = v.dup + end + + # Try to use this line and see how many more iterations you can get + # Remember to uncomment line#24 as well. + # You need to pop the array so the reference goes away. + # arrs[0].each! { |el| arr << el.dup } + end + + # Uncomment this to use with the above line#22 + # arrs.pop + + puts report + hashes << hash + i += 1 +end diff --git a/bin/bm b/bin/bm index df759c6..c4440eb 100755 --- a/bin/bm +++ b/bin/bm @@ -2,11 +2,14 @@ docker_command="docker run -m=4m -v `pwd`:`pwd` -w `pwd` hyper_iterator ruby ./benchmark/memory_bm" if [ "$1" = "each!" ] || [ "$1" = 1 ]; then - eval "$docker_command/each.rb" - eval "$docker_command/each_bang.rb" + eval "$docker_command/array_each.rb" + eval "$docker_command/array_each_bang.rb" elif [ "$1" = "each_slice!" ] || [ "$1" = 2 ]; then eval "$docker_command/each_slice.rb" eval "$docker_command/each_slice_bang.rb" +elif [ "$1" = 3 ]; then + eval "$docker_command/hash_each.rb" + eval "$docker_command/hash_each_bang.rb" else echo 'Please specify method for benchmarking. You can choose anyone from below:' echo '1. each!' diff --git a/lib/hyper_iterator.rb b/lib/hyper_iterator.rb index 077d54a..232395d 100644 --- a/lib/hyper_iterator.rb +++ b/lib/hyper_iterator.rb @@ -1,5 +1,6 @@ require_relative "./hyper_iterator/version" require_relative "./iterators/each_bang" +require_relative "./iterators/hash_each_bang" require_relative "./iterators/each_slice_bang" module HyperIterator @@ -14,5 +15,5 @@ def self.each!(iterable) end Array.include HyperIterator::EachBang -Hash.include HyperIterator::EachBang +Hash.include HyperIterator::HashEachBang Array.include HyperIterator \ No newline at end of file diff --git a/lib/iterators/hash_each_bang.rb b/lib/iterators/hash_each_bang.rb new file mode 100644 index 0000000..c1f8980 --- /dev/null +++ b/lib/iterators/hash_each_bang.rb @@ -0,0 +1,11 @@ +module HyperIterator + module HashEachBang + def each! + each do |pair| + yield pair + self[pair[0]] = nil + end + nil + end + end +end \ No newline at end of file diff --git a/test/iterators/hash_each_bang_test.rb b/test/iterators/hash_each_bang_test.rb index 94ae383..d0eb841 100644 --- a/test/iterators/hash_each_bang_test.rb +++ b/test/iterators/hash_each_bang_test.rb @@ -23,9 +23,9 @@ def test_that_it_yield_block assert vals == ord_range end - def test_that_it_remove_elements_from_array_on_the_fly + def test_that_it_sets_all_values_to_nil_on_the_fly @hash.each! {} - assert @hash.count == 0 + assert @hash.values.all?(&:nil?) end def test_that_it_returns_nil @@ -83,6 +83,6 @@ def test_that_it_can_use_class_method assert keys_1 == keys_2 assert vals_1 == vals_2 - assert hash_2.empty? + assert hash_2.values.all?(&:nil?) end end