Skip to content

Instantly share code, notes, and snippets.

@IvanShamatov
Last active October 24, 2023 11:40
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save IvanShamatov/94e78ca52f04f20c6085651345dbdfda to your computer and use it in GitHub Desktop.
Save IvanShamatov/94e78ca52f04f20c6085651345dbdfda to your computer and use it in GitHub Desktop.
require 'benchmark'
require 'benchmark/memory'
require 'dry-struct'
require 'dry-initializer'
require 'virtus'
require 'shallow_attributes'
require 'active_data'
require 'active_model'
require 'benchmark/ips'
DataResult = Data.define(
:commission,
:who_is_on_duty,
:charged,
:received,
:service_fee,
:executed_rate,
:provided_rate,
:margin
)
StructResult = Struct.new(
:commission,
:who_is_on_duty,
:charged,
:received,
:service_fee,
:executed_rate,
:provided_rate,
:margin
)
class DryInitializerResult
extend Dry::Initializer
option :commission, optional: true
option :who_is_on_duty, optional: true
option :charged, optional: true
option :received, optional: true
option :service_fee, optional: true
option :executed_rate, optional: true
option :provided_rate, optional: true
option :margin, optional: true
end
module Types
include Dry.Types()
end
class DryStructValueResult < Dry::Struct::Value
attribute :commission, Types::Strict::Float
attribute :who_is_on_duty, Types::Strict::Bool
attribute :charged, Types::Strict::Float
attribute :received, Types::Strict::Float
attribute :service_fee, Types::Strict::Float
attribute :executed_rate, Types::Strict::Float
attribute :provided_rate, Types::Strict::Float
attribute :margin, Types::Strict::Float
end
class DryStructResult < Dry::Struct
attribute :commission, Types::Strict::Float
attribute :who_is_on_duty, Types::Strict::Bool
attribute :charged, Types::Strict::Float
attribute :received, Types::Strict::Float
attribute :service_fee, Types::Strict::Float
attribute :executed_rate, Types::Strict::Float
attribute :provided_rate, Types::Strict::Float
attribute :margin, Types::Strict::Float
end
class ShallowAttributesWithDryTypesResult
include ShallowAttributes
attribute :commission, Types::Strict::Float
attribute :who_is_on_duty, Types::Strict::Bool
attribute :charged, Types::Strict::Float
attribute :received, Types::Strict::Float
attribute :service_fee, Types::Strict::Float
attribute :executed_rate, Types::Strict::Float
attribute :provided_rate, Types::Strict::Float
attribute :margin, Types::Strict::Float
end
class ShallowAttributesTypesResult
include ShallowAttributes
attribute :commission, Float
attribute :who_is_on_duty, 'Boolean'
attribute :charged, Float
attribute :received, Float
attribute :service_fee, Float
attribute :executed_rate, Float
attribute :provided_rate, Float
attribute :margin, Float
end
class VirtusResult
include Virtus.model
attribute :commission, Float
attribute :who_is_on_duty, Boolean
attribute :charged, Float
attribute :received, Float
attribute :service_fee, Float
attribute :executed_rate, Float
attribute :provided_rate, Float
attribute :margin, Float
end
class ActiveDataResult
include ActiveData::Model
attribute :commission, Float
attribute :who_is_on_duty, Boolean
attribute :charged, Float
attribute :received, Float
attribute :service_fee, Float
attribute :executed_rate, Float
attribute :provided_rate, Float
attribute :margin, Float
end
class ActiveModelResult
include ActiveModel::Model
attr_accessor :commission,
:who_is_on_duty,
:charged,
:received,
:service_fee,
:executed_rate,
:provided_rate,
:margin
end
values = {
commission: 0.02,
who_is_on_duty: true,
charged: 2355.234,
received: 235.234,
service_fee: 23.34,
executed_rate: 123000.122,
provided_rate: 122000.003,
margin: 120.3
}.freeze
n = 50000
Benchmark.memory do |x|
x.report('VirtusResult') { n.times { VirtusResult.new(values) } }
x.report('DryStructResult') { n.times { DryStructResult.new(values) } }
x.report('DryStructValueResult') { n.times { DryStructValueResult.new(values) } }
x.report('DataResult') { n.times { DataResult.new(**values) } }
x.report('StructResult') { n.times { StructResult.new(values) } }
x.report('DryInitializerResult') { n.times { DryInitializerResult.new(values) } }
x.report('ShAttsResult') { n.times { ShallowAttributesTypesResult.new(values) } }
x.report('ShAttsDryTypesResult') { n.times { ShallowAttributesWithDryTypesResult.new(values) } }
x.report('ActiveDataResult') { n.times { ActiveDataResult.new(values) } }
x.report('ActiveModelResult') { n.times { ActiveModelResult.new(values) } }
x.compare!
end
Benchmark.ips do |x|
x.report('DataResult') { DataResult.new(**values) }
x.report('StructResult') { StructResult.new(values) }
x.report('DryInitializerResult') { DryInitializerResult.new(values) }
x.report('DryStructResult') { DryStructResult.new(values) }
x.report('DryStructValueResult') { DryStructValueResult.new(values) }
x.report('VirtusResult') { VirtusResult.new(values) }
x.report('ShAttrsResult') { ShallowAttributesTypesResult.new(values) }
x.report('ShAttrsDryTypesResult') { ShallowAttributesWithDryTypesResult.new(values) }
x.report('ActiveDataResult') { ActiveDataResult.new(values) }
x.report('ActiveModelResult') { ActiveModelResult.new(values) }
x.compare!
end
# MEMORY BENCHMARK
#
# Calculating -------------------------------------
# VirtusResult 38.409M memsize ( 1.536k retained)
# 700.113k objects ( 11.000 retained)
# 50.000 strings ( 2.000 retained)
# DryStructResult 10.573M memsize ( 64.897k retained)
# 100.745k objects ( 214.000 retained)
# 50.000 strings ( 50.000 retained)
# DryStructValueResult 66.805M memsize ( 1.208k retained)
# 400.097k objects ( 17.000 retained)
# 23.000 strings ( 7.000 retained)
# DataResult 13.600M memsize ( 0.000 retained)
# 100.000k objects ( 0.000 retained)
# 0.000 strings ( 0.000 retained)
# StructResult 5.200M memsize ( 0.000 retained)
# 50.000k objects ( 0.000 retained)
# 0.000 strings ( 0.000 retained)
# DryInitializerResult 10.000M memsize ( 40.000 retained)
# 200.000k objects ( 1.000 retained)
# 0.000 strings ( 0.000 retained)
# ShAttsResult 36.400M memsize ( 248.000 retained)
# 600.002k objects ( 3.000 retained)
# 8.000 strings ( 1.000 retained)
# ShAttsDryTypesResult 32.400M memsize ( 208.000 retained)
# 500.000k objects ( 2.000 retained)
# 8.000 strings ( 1.000 retained)
# ActiveDataResult 231.200M memsize ( 1.040k retained)
# 4.900M objects ( 14.000 retained)
# 20.000 strings ( 2.000 retained)
# ActiveModelResult 20.000M memsize ( 256.000 retained)
# 450.000k objects ( 3.000 retained)
# 8.000 strings ( 1.000 retained)
# Comparison:
# StructResult: 5200000 allocated
# DryInitializerResult: 10000056 allocated - 1.92x more
# DryStructResult: 10572665 allocated - 2.03x more
# DataResult: 13600000 allocated - 2.62x more
# ActiveModelResult: 20000056 allocated - 3.85x more
# ShAttsDryTypesResult: 32399976 allocated - 6.23x more
# ShAttsResult: 36400360 allocated - 7.00x more
# VirtusResult: 38409336 allocated - 7.39x more
# DryStructValueResult: 66805240 allocated - 12.85x more
# ActiveDataResult: 231200360 allocated - 44.46x more
# IPS BENCHMARK
#
# Warming up --------------------------------------
# DataResult 174.462k i/100ms
# StructResult 389.491k i/100ms
# DryInitializerResult 87.224k i/100ms
# DryStructResult 29.820k i/100ms
# DryStructValueResult 7.197k i/100ms
# VirtusResult 7.080k i/100ms
# ShAttrsResult 15.210k i/100ms
# ShAttrsDryTypesResult
# 12.171k i/100ms
# ActiveDataResult 2.859k i/100ms
# ActiveModelResult 28.380k i/100ms
# Calculating -------------------------------------
# DataResult 1.636M (± 2.6%) i/s - 8.200M in 5.015057s
# StructResult 3.603M (± 2.7%) i/s - 18.306M in 5.084799s
# DryInitializerResult 847.515k (± 2.6%) i/s - 4.274M in 5.046375s
# DryStructResult 294.959k (± 3.0%) i/s - 1.491M in 5.059662s
# DryStructValueResult 70.253k (± 3.1%) i/s - 352.653k in 5.024650s
# VirtusResult 69.636k (± 3.2%) i/s - 354.000k in 5.088752s
# ShAttrsResult 155.235k (± 0.7%) i/s - 790.920k in 5.095200s
# ShAttrsDryTypesResult
# 126.171k (± 3.1%) i/s - 632.892k in 5.020983s
# ActiveDataResult 28.567k (± 2.4%) i/s - 142.950k in 5.007077s
# ActiveModelResult 289.265k (± 3.1%) i/s - 1.447M in 5.008408s
# Comparison:
# StructResult: 3602761.9 i/s
# DataResult: 1636110.3 i/s - 2.20x slower
# DryInitializerResult: 847514.6 i/s - 4.25x slower
# DryStructResult: 294958.5 i/s - 12.21x slower
# ActiveModelResult: 289264.7 i/s - 12.45x slower
# ShAttrsResult: 155235.5 i/s - 23.21x slower
# ShAttrsDryTypesResult: 126170.8 i/s - 28.55x slower
# DryStructValueResult: 70253.1 i/s - 51.28x slower
# VirtusResult: 69636.1 i/s - 51.74x slower
# ActiveDataResult: 28567.0 i/s - 126.12x slower
@IvanShamatov
Copy link
Author

Ruby's 3.2 Data added to the benchmark. Benchmarks updated today

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment