Last active
November 17, 2020 04:18
-
-
Save manuphatak/9ef6ba81743300ca57e93078aecc4222 to your computer and use it in GitHub Desktop.
Revisions
-
manuphatak revised this gist
Dec 27, 2019 . No changes.There are no files selected for viewing
-
manuphatak revised this gist
Dec 27, 2019 . 1 changed file with 109 additions and 41 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -48,6 +48,7 @@ def run_gc PointStruct = Struct.new(:x, :y) PointKeywordStruct = Struct.new(:x, :y, keyword_init: true) class FakedPointStruct attr_accessor :x, :y @@ -57,102 +58,169 @@ def initialize(x, y) end end class PointClassFetch attr_accessor :x, :y def initialize(args) @x = args.fetch(:x) # NOTE: Hash#fetch -> performance impact @y = args.fetch(:y) end end class PointClassKeyword attr_accessor :x, :y def initialize(x:, y:) @x = x @y = y end end puts "\n\nINITIALIZATION ==========" Benchmark.ips do |x| x.json! 'INITIALIZATION.json' x.config(suite: suite) # Create Objects as a reference value x.report("Object.new") { Object.new } x.report("FakedPointStruct") { FakedPointStruct.new(100, 200) } x.report("PointStruct") { PointStruct.new(100, 200) } x.report("PointKeywordStruct") { PointKeywordStruct.new(data) } x.report("Hash[]") { Hash[data] } x.report("PointClassFetch") { PointClassFetch.new(data) } x.report("PointClassKeyword") { PointClassKeyword.new(data) } x.report("Hash#merge") { Hash.new.merge(data) } x.report("OpenStruct") { OpenStruct.new(data) } x.compare! end puts "\n\nREAD ==========" point_struct = PointStruct.new(100, 200) point_keyword_struct = PointKeywordStruct.new(data) point_class_fetch = PointClassFetch.new(data) point_class_keyword = PointClassKeyword.new(data) point_hash = Hash[data] point_open_struct = OpenStruct.new(data) Benchmark.ips do |x| x.json! 'READ.json' x.config(suite: suite) x.report("PointStruct") { point_struct.x } x.report("PointKeywordStruct") { point_keyword_struct.x } x.report("PointClassFetch") { point_class_fetch.x } x.report("PointClassKeyword") { point_class_keyword.x } x.report("Hash#fetch") { point_hash.fetch(:x) } x.report("Hash#[]") { point_hash[:x] } x.report("OpenStruct") { point_open_struct.x } x.compare! end puts "\n\nWRITE ==========" Benchmark.ips do |x| x.json! 'WRITE.json' x.config(suite: suite) x.report("PointStruct") { point_struct.x = 1 } x.report("PointKeywordStruct") { point_keyword_struct.x = 1 } x.report("PointClassFetch") { point_class_fetch.x = 1 } x.report("PointClassKeyword") { point_class_keyword.x = 1 } x.report("Hash") { point_hash[:x] = 1 } x.report("OpenStruct") { point_open_struct.x = 1 } x.compare! end # INITIALIZATION ========== # Calculating ------------------------------------- # Object.new 232.512k i/100ms # FakedPointStruct 208.718k i/100ms # PointStruct 213.914k i/100ms # PointKeywordStruct 175.460k i/100ms # Hash[] 183.239k i/100ms # PointClassFetch 182.943k i/100ms # PointClassKeyword 131.129k i/100ms # Hash#merge 154.966k i/100ms # OpenStruct 117.413k i/100ms # ------------------------------------------------- # Object.new 7.677M (±16.1%) i/s - 37.667M # FakedPointStruct 5.919M (±12.3%) i/s - 29.221M # PointStruct 5.801M (±11.4%) i/s - 28.664M # PointKeywordStruct 4.125M (± 8.9%) i/s - 20.529M # Hash[] 4.421M (±17.4%) i/s - 21.622M # PointClassFetch 4.810M (± 7.0%) i/s - 23.966M # PointClassKeyword 2.308M (±10.0%) i/s - 11.539M # Hash#merge 2.963M (±14.7%) i/s - 14.567M # OpenStruct 1.975M (± 6.6%) i/s - 9.863M # Comparison: # Object.new: 7677097.4 i/s # FakedPointStruct: 5918849.2 i/s - 1.30x slower # PointStruct: 5801076.3 i/s - 1.32x slower # PointClassFetch: 4809859.9 i/s - 1.60x slower # Hash[]: 4420989.7 i/s - 1.74x slower # PointKeywordStruct: 4125176.9 i/s - 1.86x slower # Hash#merge: 2962687.0 i/s - 2.59x slower # PointClassKeyword: 2307777.5 i/s - 3.33x slower # OpenStruct: 1974635.6 i/s - 3.89x slower # READ ========== # Calculating ------------------------------------- # PointStruct 275.075k i/100ms # PointKeywordStruct 284.487k i/100ms # PointClassFetch 284.814k i/100ms # PointClassKeyword 274.721k i/100ms # Hash#fetch 262.639k i/100ms # Hash#[] 282.053k i/100ms # OpenStruct 244.214k i/100ms # ------------------------------------------------- # PointStruct 19.828M (± 5.1%) i/s - 99.027M # PointKeywordStruct 20.033M (± 5.2%) i/s - 100.139M # PointClassFetch 23.465M (± 3.4%) i/s - 117.343M # PointClassKeyword 22.488M (± 2.2%) i/s - 112.636M # Hash#fetch 16.465M (± 2.0%) i/s - 82.469M # Hash#[] 22.144M (± 3.0%) i/s - 110.847M # OpenStruct 10.675M (± 3.5%) i/s - 53.483M # Comparison: # PointClassFetch: 23465137.5 i/s # PointClassKeyword: 22488166.1 i/s - 1.04x slower # Hash#[]: 22143937.7 i/s - 1.06x slower # PointKeywordStruct: 20033487.9 i/s - 1.17x slower # PointStruct: 19827584.5 i/s - 1.18x slower # Hash#fetch: 16465062.4 i/s - 1.43x slower # OpenStruct: 10674642.1 i/s - 2.20x slower # WRITE ========== # Calculating ------------------------------------- # PointStruct 263.792k i/100ms # PointKeywordStruct 265.678k i/100ms # PointClassFetch 269.824k i/100ms # PointClassKeyword 282.345k i/100ms # Hash 267.091k i/100ms # OpenStruct 224.234k i/100ms # ------------------------------------------------- # PointStruct 17.523M (± 2.3%) i/s - 87.579M # PointKeywordStruct 17.653M (± 3.0%) i/s - 88.205M # PointClassFetch 21.269M (± 4.6%) i/s - 106.041M # PointClassKeyword 21.139M (± 3.7%) i/s - 105.597M # Hash 16.899M (± 4.7%) i/s - 84.401M # OpenStruct 7.053M (± 5.8%) i/s - 35.205M # Comparison: # PointClassFetch: 21268766.9 i/s # PointClassKeyword: 21138642.2 i/s - 1.01x slower # PointKeywordStruct: 17652879.3 i/s - 1.20x slower # PointStruct: 17522748.0 i/s - 1.21x slower # Hash: 16899040.6 i/s - 1.26x slower # OpenStruct: 7053426.1 i/s - 3.02x slower -
manuphatak created this gist
Dec 27, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,158 @@ # Response to: # http://blog.honeybadger.io/how-openstruct-and-hashes-can-kill-performance/ # # It's not faire to use `Hash.new.merge(data)` if you can `Hash[data]`. # `Hash[data]` is way faster! Lets compare! # # Read more: http://ruby-doc.org/core-2.2.0/Hash.html#method-c-5B-5D # # [UPDATE] # # * Disable GC for each report require 'benchmark/ips' require 'ostruct' # Enable and start GC before each job run. Disable GC afterwards. # # Inspired by https://www.omniref.com/ruby/2.2.1/symbols/Benchmark/bm?#annotation=4095926&line=182 class GCSuite def warming(*) run_gc end def running(*) run_gc end def warmup_stats(*) end def add_report(*) end private def run_gc GC.enable GC.start GC.disable end end suite = GCSuite.new data = { x: 100, y: 200 } PointStruct = Struct.new(:x, :y) class FakedPointStruct attr_accessor :x, :y def initialize(x, y) @x = x @y = y end end class PointClass attr_accessor :x, :y def initialize(args) @x = args.fetch(:x) # NOTE: Hash#fetch -> performance impact @y = args.fetch(:y) end end puts "\n\nINITIALIZATION ==========" Benchmark.ips do |x| x.config(suite: suite) # Create Objects as a reference value x.report("Object.new") { Object.new } x.report("FakedPointStruct") { FakedPointStruct.new(100, 200) } x.report("PointStruct") { PointStruct.new(100, 200) } x.report("Hash[]") { Hash[data] } x.report("PointClass") { PointClass.new(data) } x.report("Hash#merge") { Hash.new.merge(data) } x.report("OpenStruct") { OpenStruct.new(data) } end puts "\n\nREAD ==========" point_struct = PointStruct.new(100, 200) point_class = PointClass.new(data) point_hash = Hash[data] point_open_struct = OpenStruct.new(data) Benchmark.ips do |x| x.config(suite: suite) x.report("PointStruct") { point_struct.x } x.report("PointClass") { point_class.x } x.report("Hash#fetch") { point_hash.fetch(:x) } x.report("Hash#[]") { point_hash[:x] } x.report("OpenStruct") { point_open_struct.x } end puts "\n\nWRITE ==========" Benchmark.ips do |x| x.config(suite: suite) x.report("PointStruct") { point_struct.x = 1 } x.report("PointClass") { point_class.x = 1 } x.report("Hash") { point_hash[:x] = 1 } x.report("OpenStruct") { point_open_struct.x = 1 } end # INITIALIZATION ========== # Calculating ------------------------------------- # Object.new 146.142k i/100ms # FakedPointStruct 138.237k i/100ms # PointStruct 138.366k i/100ms # Hash[] 134.258k i/100ms # PointClass 117.585k i/100ms # Hash#merge 75.923k i/100ms # OpenStruct 13.386k i/100ms # ------------------------------------------------- # Object.new 5.711M (± 4.9%) i/s - 28.498M # FakedPointStruct 4.553M (± 0.2%) i/s - 22.809M # PointStruct 4.379M (± 6.8%) i/s - 21.862M # Hash[] 3.847M (± 6.8%) i/s - 19.199M # PointClass 3.169M (± 2.2%) i/s - 15.874M # Hash#merge 1.319M (± 2.4%) i/s - 6.605M # OpenStruct 157.615k (± 3.4%) i/s - 789.774k # # # READ ========== # Calculating ------------------------------------- # PointStruct 136.199k i/100ms # PointClass 151.109k i/100ms # Hash#fetch 145.969k i/100ms # Hash#[] 151.614k i/100ms # OpenStruct 127.398k i/100ms # ------------------------------------------------- # PointStruct 10.961M (± 3.1%) i/s - 45.218M # PointClass 11.606M (± 3.5%) i/s - 58.026M # Hash#fetch 8.123M (± 5.4%) i/s - 40.433M # Hash#[] 10.142M (± 1.6%) i/s - 50.791M # OpenStruct 6.657M (± 6.8%) i/s - 33.123M # # # WRITE ========== # Calculating ------------------------------------- # PointStruct 162.156k i/100ms # PointClass 182.713k i/100ms # Hash 171.868k i/100ms # OpenStruct 128.931k i/100ms # ------------------------------------------------- # PointStruct 9.015M (± 1.0%) i/s - 45.079M # PointClass 10.911M (± 3.5%) i/s - 54.448M # Hash 8.741M (± 5.7%) i/s - 43.483M # OpenStruct 4.542M (± 0.6%) i/s - 22.821M