Skip to content

Instantly share code, notes, and snippets.

@argami
Last active January 25, 2023 11:55
Show Gist options
  • Save argami/8081bc97bb56a60da2e755dc157776c5 to your computer and use it in GitHub Desktop.
Save argami/8081bc97bb56a60da2e755dc157776c5 to your computer and use it in GitHub Desktop.

Revisions

  1. argami revised this gist Jan 25, 2023. 1 changed file with 84 additions and 0 deletions.
    84 changes: 84 additions & 0 deletions results.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@

    INITIALIZATION ==========
    Warming up --------------------------------------
    OpenStruct 7.763k i/100ms
    Struct 765.889k i/100ms
    Class 296.770k i/100ms
    Hash 451.498k i/100ms
    Calculating -------------------------------------
    OpenStruct 77.672k (± 2.7%) i/s - 388.150k in 5.001142s
    Struct 7.618M (± 1.4%) i/s - 38.294M in 5.027768s
    Class 2.787M (±11.1%) i/s - 13.948M in 5.100858s
    Hash 4.338M (± 9.1%) i/s - 21.672M in 5.055607s

    Comparison:
    Struct: 7618131.0 i/s
    Hash: 4337601.8 i/s - 1.76x (± 0.00) slower
    Class: 2786751.9 i/s - 2.73x (± 0.00) slower
    OpenStruct: 77672.0 i/s - 98.08x (± 0.00) slower



    READ ==========
    Warming up --------------------------------------
    OpenStruct 1.189M i/100ms
    Struct 1.927M i/100ms
    Class 1.978M i/100ms
    Hash 769.667k i/100ms
    Calculating -------------------------------------
    OpenStruct 11.407M (± 7.5%) i/s - 57.058M in 5.037030s
    Struct 18.108M (± 9.9%) i/s - 90.582M in 5.079644s
    Class 19.829M (± 2.2%) i/s - 100.895M in 5.090690s
    Hash 13.089M (± 2.1%) i/s - 65.422M in 5.000433s

    Comparison:
    Class: 19828999.2 i/s
    Struct: 18107923.1 i/s - same-ish: difference falls within error
    Hash: 13089378.4 i/s - 1.51x (± 0.00) slower
    OpenStruct: 11406605.9 i/s - 1.74x (± 0.00) slower



    WRITE ==========
    Warming up --------------------------------------
    OpenStruct 414.666k i/100ms
    Struct 1.347M i/100ms
    Class 1.254M i/100ms
    Hash 800.079k i/100ms
    Calculating -------------------------------------
    OpenStruct 4.136M (± 0.5%) i/s - 20.733M in 5.013139s
    Struct 13.239M (± 3.5%) i/s - 67.370M in 5.095966s
    Class 12.363M (±14.1%) i/s - 60.171M in 5.051611s
    Hash 7.970M (± 5.6%) i/s - 40.004M in 5.039890s

    Comparison:
    Struct: 13238563.6 i/s
    Class: 12362712.8 i/s - same-ish: difference falls within error
    Hash: 7969707.0 i/s - 1.66x (± 0.00) slower
    OpenStruct: 4135881.8 i/s - 3.20x (± 0.00) slower



    ############# MEMORY ==========


    INITIALIZATION ==========
    Calculating -------------------------------------
    OpenStruct 4.384k memsize ( 0.000 retained)
    45.000 objects ( 0.000 retained)
    6.000 strings ( 0.000 retained)
    Struct 88.000 memsize ( 0.000 retained)
    1.000 objects ( 0.000 retained)
    0.000 strings ( 0.000 retained)
    Class 88.000 memsize ( 0.000 retained)
    1.000 objects ( 0.000 retained)
    0.000 strings ( 0.000 retained)
    Hash 208.000 memsize ( 0.000 retained)
    2.000 objects ( 0.000 retained)
    0.000 strings ( 0.000 retained)

    Comparison:
    Struct: 88 allocated
    Class: 88 allocated - same
    Hash: 208 allocated - 2.36x more
    OpenStruct: 4384 allocated - 49.82x more
  2. argami created this gist Jan 25, 2023.
    7 changes: 7 additions & 0 deletions Gemfile
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    # frozen_string_literal: true

    source "https://rubygems.org"

    gem "benchmark-ips"
    gem "ruby-progressbar"
    gem "benchmark-memory"
    90 changes: 90 additions & 0 deletions openstruct_bench.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    # frozen_string_literal: true

    require "bundler"
    Bundler.require
    require "ostruct"

    data = { x: 100, y: 200, z: "some other data", a: "more text data", b: 1100.00, c: Time.now }

    PointStruct = Struct.new(:x, :y, :z, :a, :b, :c)

    class PointClass
    attr_accessor :x, :y, :z, :a, :b, :c

    def initialize(args)
    @x = args.fetch(:x)
    @y = args.fetch(:y)
    @z = args.fetch(:z)
    @a = args.fetch(:a)
    @b = args.fetch(:b)
    @c = args.fetch(:c)
    end
    end

    puts "\n\nINITIALIZATION =========="

    Benchmark.ips do |x|
    x.report("OpenStruct") { OpenStruct.new(data) }
    x.report("Struct") { PointStruct.new(data) }
    x.report("Class") { PointClass.new(data) }
    x.report("Hash") { {}.merge(data) }

    x.compare!
    end

    puts "\n\nREAD =========="

    point_struct = PointStruct.new(data)
    point_class = PointClass.new(data)
    point_hash = {}.merge(data)
    point_open_struct = OpenStruct.new(data)

    Benchmark.ips do |x|
    x.config(warmup: 90) if RUBY_ENGINE == "jruby"
    x.report("OpenStruct") { point_open_struct.z }
    x.report("Struct") { point_struct.z }
    x.report("Class") { point_class.z }
    x.report("Hash") { point_hash.fetch(:z) }

    x.compare!
    end

    puts "\n\nWRITE =========="

    Benchmark.ips do |x|
    x.report("OpenStruct") do
    point_open_struct.x = "even more data"
    point_open_struct.z = 1000.00
    point_open_struct.b = 100
    end
    x.report("Struct") do
    point_struct.x = "even more data"
    point_struct.z = 1000.00
    point_struct.b = 100
    end
    x.report("Class") do
    point_class.x = "even more data"
    point_class.z = 1000.00
    point_class.b = 100
    end
    x.report("Hash") do
    point_hash[:x] = "even more data"
    point_hash[:z] = 1000.00
    point_hash[:b] = 100
    end

    x.compare!
    end

    puts "\n\n############# MEMORY =========="

    puts "\n\nINITIALIZATION =========="

    Benchmark.memory do |x|
    x.report("OpenStruct") { OpenStruct.new(data) }
    x.report("Struct") { PointStruct.new(data) }
    x.report("Class") { PointClass.new(data) }
    x.report("Hash") { {}.merge(data) }

    x.compare!
    end