Science Score: 44.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
✓CITATION.cff file
Found CITATION.cff file -
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
○DOI references
-
○Academic publication links
-
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (8.5%) to scientific vocabulary
Keywords
benchmark
micro
speed
Last synced: 6 months ago
·
JSON representation
·
Repository
A collection of micro benchmarks.
Basic Info
- Host: GitHub
- Owner: bkuhlmann
- License: other
- Language: Ruby
- Default Branch: main
- Homepage: https://alchemists.io/projects/benchmarks
- Size: 600 KB
Statistics
- Stars: 6
- Watchers: 2
- Forks: 0
- Open Issues: 0
- Releases: 0
Topics
benchmark
micro
speed
Created about 7 years ago
· Last pushed 6 months ago
Metadata Files
Readme
Funding
License
Citation
README.adoc
:toc: macro
:toclevels: 5
:figure-caption!:
= Benchmarks
Benchmarks is a collection of Ruby micro benchmarks which can be cloned and run locally or used as
an information point of reference. The various statistics on Ruby performance captured within this
project may or may not surprise you.
toc::[]
== Features
* Uses link:https://github.com/evanphx/benchmark-ips[Benchmark IPS] to calculate CPU/speed results.
* Each script is independently executable.
== Requirements
. link:https://www.ruby-lang.org[Ruby]
== Setup
To install, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/benchmarks.git
cd benchmarks
git checkout 5.4.0
bin/setup
----
== Usage
All benchmark scripts are found within the `scripts` folder and you can run any benchmark using a relative or absolute file path. Example:
=== scripts/arrays/concatenation
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
a = %w[one two three]
b = %w[four five six]
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "#+" do
a + b
end
benchmark.report "#+=" do
duplicate = a.dup
duplicate += b
end
benchmark.report "#concat" do
a.dup.concat b
end
benchmark.report "#|" do
a | b
end
benchmark.report "#<< + #flatten" do
(a.dup << b).flatten
end
benchmark.report "splat + #flatten" do
[a, *b].flatten
end
benchmark.report "multi-splat" do
[*a, *b]
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#+ 2.130M i/100ms
#+= 927.861k i/100ms
#concat 691.057k i/100ms
#| 483.602k i/100ms
#<< + #flatten 203.055k i/100ms
splat + #flatten 212.664k i/100ms
multi-splat 903.880k i/100ms
Calculating -------------------------------------
#+ 23.159M (± 0.7%) i/s (43.18 ns/i) - 117.130M in 5.057953s
#+= 9.970M (± 0.8%) i/s (100.30 ns/i) - 50.104M in 5.025637s
#concat 7.333M (± 1.6%) i/s (136.37 ns/i) - 37.317M in 5.090383s
#| 4.824M (± 1.8%) i/s (207.30 ns/i) - 24.180M in 5.014471s
#<< + #flatten 2.101M (± 1.1%) i/s (475.99 ns/i) - 10.559M in 5.026496s
splat + #flatten 2.156M (± 1.2%) i/s (463.80 ns/i) - 10.846M in 5.031006s
multi-splat 9.786M (± 2.0%) i/s (102.19 ns/i) - 49.713M in 5.082000s
Comparison:
#+: 23158921.5 i/s
#+=: 9970346.4 i/s - 2.32x slower
multi-splat: 9786149.7 i/s - 2.37x slower
#concat: 7332786.6 i/s - 3.16x slower
#|: 4823810.9 i/s - 4.80x slower
splat + #flatten: 2156124.7 i/s - 10.74x slower
#<< + #flatten: 2100889.3 i/s - 11.02x slower
....
=== scripts/arrays/search
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
list = %w[one two three four five six seven eight nine ten]
pattern = /t/
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("#grep") { list.grep pattern }
benchmark.report("#select") { list.select { |value| value.match? pattern } }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#grep 198.448k i/100ms
#select 237.432k i/100ms
Calculating -------------------------------------
#grep 1.997M (± 1.3%) i/s (500.69 ns/i) - 10.121M in 5.068227s
#select 2.468M (± 0.9%) i/s (405.26 ns/i) - 12.346M in 5.003928s
Comparison:
#select: 2467557.1 i/s
#grep: 1997260.3 i/s - 1.24x slower
....
=== scripts/bindings
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Test
def self.with_binding(end:) = binding.local_variable_get(:end)
def self.with_pinning(end:) = {end:}[:end]
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Binding") { Test.with_binding end: 1 }
benchmark.report("Pinning") { Test.with_pinning end: 1 }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Binding 685.023k i/100ms
Pinning 1.868M i/100ms
Calculating -------------------------------------
Binding 7.416M (± 2.1%) i/s (134.85 ns/i) - 37.676M in 5.082785s
Pinning 20.890M (± 2.7%) i/s (47.87 ns/i) - 104.605M in 5.011139s
Comparison:
Pinning: 20890279.6 i/s
Binding: 7415714.9 i/s - 2.82x slower
....
=== scripts/constants/lookup
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
CONSTANTS = Hash.new
module Constants
1_000.times { |index| CONSTANTS["EXAMPLE_#{index}"] = const_set "EXAMPLE_#{index}", index }
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("#[]") { CONSTANTS["EXAMPLE_666"] }
benchmark.report("Module.get (symbol)") { Constants.const_get :EXAMPLE_666 }
benchmark.report("Module.get (string)") { Constants.const_get "EXAMPLE_666" }
benchmark.report("Object.get") { Object.const_get "Constants::EXAMPLE_666" }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#[] 2.897M i/100ms
Module.get (symbol) 3.406M i/100ms
Module.get (string) 1.669M i/100ms
Object.get 1.011M i/100ms
Calculating -------------------------------------
#[] 33.548M (± 0.9%) i/s (29.81 ns/i) - 168.050M in 5.009641s
Module.get (symbol) 42.820M (± 0.1%) i/s (23.35 ns/i) - 214.596M in 5.011591s
Module.get (string) 18.319M (± 0.3%) i/s (54.59 ns/i) - 91.822M in 5.012443s
Object.get 11.053M (± 0.2%) i/s (90.48 ns/i) - 55.582M in 5.028808s
Comparison:
Module.get (symbol): 42820077.0 i/s
#[]: 33548240.7 i/s - 1.28x slower
Module.get (string): 18319033.6 i/s - 2.34x slower
Object.get: 11052680.4 i/s - 3.87x slower
....
=== scripts/delegates
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
require "delegate"
require "forwardable"
module Echo
def self.call(message) = message
end
class ForwardExample
def initialize operation
@operation = operation
end
def call(...) = operation.call(...)
private
attr_reader :operation
end
class DelegateExample
extend Forwardable
delegate %i[call] => :operation
def initialize operation
@operation = operation
end
private
attr_reader :operation
end
class SimpleExample < SimpleDelegator
end
class ClassExample < DelegateClass Echo
end
message = "A test."
forward_example = ForwardExample.new Echo
deletate_example = DelegateExample.new Echo
simple_example = SimpleExample.new Echo
class_example = ClassExample.new Echo
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Forward") { forward_example.call message }
benchmark.report("Delegate") { deletate_example.call message }
benchmark.report("Simple Delegator") { simple_example.call message }
benchmark.report("Delegate Class") { class_example.call message }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Forward 2.172M i/100ms
Delegate 2.005M i/100ms
Simple Delegator 494.121k i/100ms
Delegate Class 486.884k i/100ms
Calculating -------------------------------------
Forward 26.423M (± 0.2%) i/s (37.85 ns/i) - 132.481M in 5.013922s
Delegate 23.553M (± 0.5%) i/s (42.46 ns/i) - 118.295M in 5.022589s
Simple Delegator 5.399M (± 0.9%) i/s (185.23 ns/i) - 27.177M in 5.034498s
Delegate Class 5.404M (± 0.6%) i/s (185.04 ns/i) - 27.266M in 5.045399s
Comparison:
Forward: 26422769.4 i/s
Delegate: 23553279.8 i/s - 1.12x slower
Delegate Class: 5404232.5 i/s - 4.89x slower
Simple Delegator: 5398560.6 i/s - 4.89x slower
....
=== scripts/functions/blocks
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Example = Class.new do
def echo_implicit text
yield
text
end
def echo_implicit_guard text
yield if block_given?
text
end
def echo_explicit text, &block
yield block
text
end
def echo_explicit_guard text, &block
yield block if block
text
end
end
block_example = Example.new
lambda_example = -> text { text }
proc_example = proc { |text| text }
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "Block (implicit)" do
block_example.echo_implicit("hi") { "test" }
end
benchmark.report "Block (implicit guard)" do
block_example.echo_implicit_guard("hi") { "test" }
end
benchmark.report "Block (explicit)" do
block_example.echo_explicit("hi") { "test" }
end
benchmark.report "Block (explicit guard)" do
block_example.echo_explicit_guard("hi") { "test" }
end
benchmark.report "Lambda" do
lambda_example.call "test"
end
benchmark.report "Proc" do
proc_example.call "test"
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Block (implicit) 4.215M i/100ms
Block (implicit guard)
3.820M i/100ms
Block (explicit) 787.233k i/100ms
Block (explicit guard)
783.153k i/100ms
Lambda 2.806M i/100ms
Proc 2.983M i/100ms
Calculating -------------------------------------
Block (implicit) 59.814M (± 0.2%) i/s (16.72 ns/i) - 299.269M in 5.003373s
Block (implicit guard)
56.952M (± 0.4%) i/s (17.56 ns/i) - 286.516M in 5.030941s
Block (explicit) 8.892M (± 1.0%) i/s (112.46 ns/i) - 44.872M in 5.046771s
Block (explicit guard)
8.804M (± 1.0%) i/s (113.59 ns/i) - 44.640M in 5.070946s
Lambda 34.991M (± 0.9%) i/s (28.58 ns/i) - 176.772M in 5.052370s
Proc 35.366M (± 0.9%) i/s (28.28 ns/i) - 178.993M in 5.061491s
Comparison:
Block (implicit): 59813544.8 i/s
Block (implicit guard): 56951704.4 i/s - 1.05x slower
Proc: 35366437.5 i/s - 1.69x slower
Lambda: 34990583.2 i/s - 1.71x slower
Block (explicit): 8892108.2 i/s - 6.73x slower
Block (explicit guard): 8803962.5 i/s - 6.79x slower
....
=== scripts/functions/static
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
class_example = Class.new do
def self.call(first, second) = first + second
end
module_example = Module.new do
module_function
def call(first, second) = first + second
end
function_example = -> first, second { first + second }
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Class") { class_example.call 10, 20 }
benchmark.report("Module") { module_example.call 10, 20 }
benchmark.report("Function") { function_example.call 10, 20 }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Class 4.586M i/100ms
Module 4.072M i/100ms
Function 2.714M i/100ms
Calculating -------------------------------------
Class 62.525M (± 0.4%) i/s (15.99 ns/i) - 316.450M in 5.061239s
Module 62.654M (± 0.2%) i/s (15.96 ns/i) - 313.576M in 5.004938s
Function 31.392M (± 2.1%) i/s (31.86 ns/i) - 157.390M in 5.015900s
Comparison:
Module: 62653616.0 i/s
Class: 62525065.5 i/s - same-ish: difference falls within error
Function: 31391523.8 i/s - 2.00x slower
....
=== scripts/hashes/lookup
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
example = {a: 1, b: 2, c: 3}
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("#[]") { example[:b] }
benchmark.report("#fetch") { example.fetch :b }
benchmark.report("#fetch (default)") { example.fetch :b, "default" }
benchmark.report("#fetch (block)") { example.fetch(:b) { "default" } }
benchmark.report("#dig") { example.dig :b }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#[] 4.108M i/100ms
#fetch 3.613M i/100ms
#fetch (default) 3.746M i/100ms
#fetch (block) 3.709M i/100ms
#dig 4.047M i/100ms
Calculating -------------------------------------
#[] 51.006M (± 0.3%) i/s (19.61 ns/i) - 258.811M in 5.074111s
#fetch 44.278M (± 0.6%) i/s (22.58 ns/i) - 224.011M in 5.059357s
#fetch (default) 44.317M (± 0.3%) i/s (22.56 ns/i) - 224.757M in 5.071557s
#fetch (block) 43.807M (± 0.4%) i/s (22.83 ns/i) - 222.555M in 5.080432s
#dig 48.337M (± 0.1%) i/s (20.69 ns/i) - 242.803M in 5.023111s
Comparison:
#[]: 51006430.3 i/s
#dig: 48337145.4 i/s - 1.06x slower
#fetch (default): 44317430.9 i/s - 1.15x slower
#fetch: 44278312.1 i/s - 1.15x slower
#fetch (block): 43807023.1 i/s - 1.16x slower
....
=== scripts/hashes/merge
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
extra = {b: 2}
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Splat") { {a: 1, **extra} }
benchmark.report("Merge") { {a: 1}.merge extra }
benchmark.report("Merge!") { {a: 1}.merge! extra }
benchmark.report("Dup Merge!") { {a: 1}.dup.merge! extra }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Splat 1.220M i/100ms
Merge 972.824k i/100ms
Merge! 1.398M i/100ms
Dup Merge! 728.688k i/100ms
Calculating -------------------------------------
Splat 14.035M (± 1.5%) i/s (71.25 ns/i) - 70.757M in 5.042521s
Merge 10.595M (± 1.4%) i/s (94.38 ns/i) - 53.505M in 5.050960s
Merge! 14.980M (± 1.2%) i/s (66.76 ns/i) - 75.471M in 5.038965s
Dup Merge! 7.787M (± 1.1%) i/s (128.41 ns/i) - 39.349M in 5.053630s
Comparison:
Merge!: 14979505.8 i/s
Splat: 14035287.2 i/s - 1.07x slower
Merge: 10595050.3 i/s - 1.41x slower
Dup Merge!: 7787275.3 i/s - 1.92x slower
....
=== scripts/hashes/reduce
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
numbers = {
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
six: 6,
seven: 7,
eight: 8,
nine: 9,
ten: 10
}
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "Reduce" do
numbers.reduce({}) { |collection, (key, value)| collection.merge! value => key }
end
benchmark.report "With Object" do
numbers.each.with_object({}) { |(key, value), collection| collection[value] = key }
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Reduce 64.415k i/100ms
With Object 100.991k i/100ms
Calculating -------------------------------------
Reduce 656.529k (± 1.0%) i/s (1.52 μs/i) - 3.285M in 5.004376s
With Object 1.032M (± 0.8%) i/s (969.23 ns/i) - 5.252M in 5.090269s
Comparison:
With Object: 1031743.5 i/s
Reduce: 656529.5 i/s - 1.57x slower
....
=== scripts/loops
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
collection = (1..1_000).to_a
sum = 0
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "for" do
for number in collection do
sum += number
end
end
benchmark.report "#each" do
collection.each { |number| sum += number }
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
for 19.313k i/100ms
#each 21.611k i/100ms
Calculating -------------------------------------
for 193.383k (± 0.1%) i/s (5.17 μs/i) - 984.963k in 5.093344s
#each 215.690k (± 0.1%) i/s (4.64 μs/i) - 1.081M in 5.009754s
Comparison:
#each: 215689.6 i/s
for: 193382.6 i/s - 1.12x slower
....
=== scripts/methods/define_method
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
require "forwardable"
Person = Class.new do
def initialize first, last
@first = first
@last = last
end
def full_name
"#{first} #{last}"
end
private
attr_reader :first, :last
end
Example = Class.new Person do
extend Forwardable
define_method :unbound_full_name, Person.instance_method(:full_name)
delegate %i[full_name] => :person
def initialize first, last, person: Person.new(first, last)
super first, last
@person = person
end
def wrapped_full_name
person.full_name
end
private
attr_reader :first, :last, :person
end
example = Example.new "Jill", "Doe"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Wrapped") { example.wrapped_full_name }
benchmark.report("Defined") { example.unbound_full_name }
benchmark.report("Delegated") { example.full_name }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Wrapped 1.582M i/100ms
Defined 1.639M i/100ms
Delegated 1.150M i/100ms
Calculating -------------------------------------
Wrapped 17.189M (± 1.0%) i/s (58.18 ns/i) - 87.037M in 5.064110s
Defined 17.717M (± 1.0%) i/s (56.44 ns/i) - 90.126M in 5.087374s
Delegated 12.469M (± 0.5%) i/s (80.20 ns/i) - 63.277M in 5.074680s
Comparison:
Defined: 17717413.2 i/s
Wrapped: 17188761.0 i/s - 1.03x slower
Delegated: 12469384.0 i/s - 1.42x slower
....
=== scripts/methods/method_proc
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Example = Class.new do
def initialize words
@words = words
@first_word = words.first
end
def direct_single
say first_word
end
def direct_multiple
words.each { |word| say word }
end
def proc_single
method(:say).call first_word
end
def proc_multiple
words.each { |word| method(:say).call word }
end
def method_to_proc_single
first_word.then(&method(:say))
end
def method_to_proc_multiple
words.each(&method(:say))
end
private
attr_reader :words, :first_word
def say phrase
"You said: #{phrase}."
end
end
example = Example.new %w[one two three]
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Direct (s)") { example.direct_single }
benchmark.report("Direct (m)") { example.direct_multiple }
benchmark.report("Proc (s)") { example.proc_single }
benchmark.report("Proc (m)") { example.proc_multiple }
benchmark.report("Method To Proc (s)") { example.method_to_proc_single }
benchmark.report("Method To Proc (m)") { example.method_to_proc_multiple }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Direct (s) 1.686M i/100ms
Direct (m) 581.545k i/100ms
Proc (s) 771.008k i/100ms
Proc (m) 277.976k i/100ms
Method To Proc (s) 351.620k i/100ms
Method To Proc (m) 222.732k i/100ms
Calculating -------------------------------------
Direct (s) 18.494M (± 1.0%) i/s (54.07 ns/i) - 92.704M in 5.013031s
Direct (m) 6.220M (± 1.4%) i/s (160.76 ns/i) - 31.403M in 5.049559s
Proc (s) 8.887M (± 0.9%) i/s (112.53 ns/i) - 44.718M in 5.032556s
Proc (m) 2.913M (± 1.0%) i/s (343.32 ns/i) - 14.733M in 5.058585s
Method To Proc (s) 3.771M (± 1.5%) i/s (265.18 ns/i) - 18.987M in 5.036310s
Method To Proc (m) 2.298M (± 0.9%) i/s (435.17 ns/i) - 11.582M in 5.040560s
Comparison:
Direct (s): 18494466.4 i/s
Proc (s): 8886651.1 i/s - 2.08x slower
Direct (m): 6220285.8 i/s - 2.97x slower
Method To Proc (s): 3770971.6 i/s - 4.90x slower
Proc (m): 2912720.9 i/s - 6.35x slower
Method To Proc (m): 2297978.5 i/s - 8.05x slower
....
=== scripts/methods/scoped_send
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Example
module_function
def add(first = 1, second = 2) = first + second
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Public") { Example.public_send :add }
benchmark.report("Private") { Example.__send__ :add }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Public 2.011M i/100ms
Private 4.220M i/100ms
Calculating -------------------------------------
Public 23.979M (± 1.1%) i/s (41.70 ns/i) - 120.645M in 5.031991s
Private 61.137M (± 0.4%) i/s (16.36 ns/i) - 308.063M in 5.038936s
Comparison:
Private: 61137450.6 i/s
Public: 23978548.9 i/s - 2.55x slower
....
=== scripts/methods/send
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Static
def self.call = rand > 0.5 ? one : two
def self.one = 1
def self.two = 2
end
module Dynamic
def self.with_strings = public_send rand > 0.5 ? "one" : "two"
def self.with_symbols = public_send rand > 0.5 ? :one : :two
def self.one = 1
def self.two = 2
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Static") { Static.call }
benchmark.report("Dynamic (strings)") { Dynamic.with_strings }
benchmark.report("Dynamic (symbols)") { Dynamic.with_symbols }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Static 2.126M i/100ms
Dynamic (strings) 973.273k i/100ms
Dynamic (symbols) 1.256M i/100ms
Calculating -------------------------------------
Static 26.137M (± 5.6%) i/s (38.26 ns/i) - 131.819M in 5.058540s
Dynamic (strings) 11.631M (± 0.9%) i/s (85.98 ns/i) - 58.396M in 5.021134s
Dynamic (symbols) 16.000M (± 1.7%) i/s (62.50 ns/i) - 80.395M in 5.026229s
Comparison:
Static: 26137140.5 i/s
Dynamic (symbols): 16000110.8 i/s - 1.63x slower
Dynamic (strings): 11631159.4 i/s - 2.25x slower
....
=== scripts/numerics
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "bigdecimal"
gem "benchmark-ips"
end
require "bigdecimal"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Integer") { 1 + 0 }
benchmark.report("Float") { 0.1 + 0 }
benchmark.report("Rational") { (1 / 1r) + 0 }
benchmark.report("BigDecimal") { BigDecimal("0.1") + 0 }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Integer 4.818M i/100ms
Float 4.688M i/100ms
Rational 1.440M i/100ms
BigDecimal 285.130k i/100ms
Calculating -------------------------------------
Integer 72.057M (± 2.9%) i/s (13.88 ns/i) - 361.327M in 5.019619s
Float 62.474M (± 0.7%) i/s (16.01 ns/i) - 314.066M in 5.027353s
Rational 15.063M (± 0.3%) i/s (66.39 ns/i) - 76.338M in 5.067855s
BigDecimal 2.871M (± 0.9%) i/s (348.31 ns/i) - 14.542M in 5.065332s
Comparison:
Integer: 72057483.7 i/s
Float: 62474330.5 i/s - 1.15x slower
Rational: 15063323.3 i/s - 4.78x slower
BigDecimal: 2871025.0 i/s - 25.10x slower
....
=== scripts/pattern_matching/multiple_type_check
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("include?") { [String, Symbol].include? :test.class }
benchmark.report("in") { :test in String | Symbol }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
include? 3.306M i/100ms
in 2.232M i/100ms
Calculating -------------------------------------
include? 39.476M (± 0.2%) i/s (25.33 ns/i) - 198.332M in 5.024176s
in 26.164M (± 0.1%) i/s (38.22 ns/i) - 131.686M in 5.033138s
Comparison:
include?: 39475647.2 i/s
in: 26163792.0 i/s - 1.51x slower
....
=== scripts/pattern_matching/single_type_check
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("is_a?") { :test.is_a? Symbol }
benchmark.report("in") { :test in Symbol }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
is_a? 4.392M i/100ms
in 3.021M i/100ms
Calculating -------------------------------------
is_a? 71.209M (± 0.2%) i/s (14.04 ns/i) - 360.148M in 5.057619s
in 38.621M (± 1.2%) i/s (25.89 ns/i) - 193.351M in 5.007114s
Comparison:
is_a?: 71209235.1 i/s
in: 38621042.8 i/s - 1.84x slower
....
=== scripts/refinements/import
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Import
def dud = true
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "With" do
Module.new { refine(String) { import_methods Import } }
end
benchmark.report "Without" do
Module.new { def dud = true }
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
With 48.000 i/100ms
Without 409.598k i/100ms
Calculating -------------------------------------
With 282.342 (± 0.4%) i/s (3.54 ms/i) - 1.440k in 5.100310s
Without 4.139M (± 1.7%) i/s (241.60 ns/i) - 20.889M in 5.048344s
Comparison:
Without: 4139064.0 i/s
With: 282.3 i/s - 14659.74x slower
....
=== scripts/refinements/initialize
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Refines
refine String do
def dud = true
end
end
class With
using Refines
def initialize value = "demo"
@value = value
end
end
class Without
def initialize value = "demo"
@value = value
end
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("With") { With.new }
benchmark.report("Without") { Without.new }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
With 1.462M i/100ms
Without 1.463M i/100ms
Calculating -------------------------------------
With 16.904M (± 0.9%) i/s (59.16 ns/i) - 84.773M in 5.015288s
Without 16.739M (± 1.1%) i/s (59.74 ns/i) - 84.878M in 5.071267s
Comparison:
With: 16904250.5 i/s
Without: 16739147.2 i/s - same-ish: difference falls within error
....
=== scripts/refinements/message
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
module Refines
refine String do
def dud = true
end
end
module With
using Refines
def self.call(value) = value.dud
end
module Without
def self.call(value) = value
end
value = "demo"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("With") { With.call value }
benchmark.report("Without") { Without.call value }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
With 2.722M i/100ms
Without 4.843M i/100ms
Calculating -------------------------------------
With 37.130M (± 0.3%) i/s (26.93 ns/i) - 187.803M in 5.058008s
Without 68.976M (± 4.2%) i/s (14.50 ns/i) - 348.707M in 5.067107s
Comparison:
Without: 68975872.3 i/s
With: 37130284.9 i/s - 1.86x slower
....
=== scripts/refinements/refine
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "With" do
Module.new do
refine String do
def dud = true
end
end
end
benchmark.report "Without" do
Module.new do
def dud = true
end
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
With 52.000 i/100ms
Without 402.935k i/100ms
Calculating -------------------------------------
With 284.492 (± 0.7%) i/s (3.52 ms/i) - 1.456k in 5.118210s
Without 4.116M (± 1.8%) i/s (242.94 ns/i) - 20.953M in 5.091996s
Comparison:
Without: 4116202.1 i/s
With: 284.5 i/s - 14468.62x slower
....
=== scripts/strings/concatenation
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
one = "One"
two = "Two"
three = "Three"
four = "Four"
five = "Five"
six = "Six"
seven = "Seven"
eight = "Eight"
nine = "Nine"
ten = "Ten"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "Implicit (<)" do
"One" "Two"
end
benchmark.report "Implicit (>)" do
"One" "Two" "Three" "Four" "Five" "Six" "Seven" "Eight" "Nine" "Ten"
end
benchmark.report "Interpolation (<)" do
"#{one} #{two}"
end
benchmark.report "Interpolation (>)" do
"#{one} #{two} #{three} #{four} #{five} #{six} #{seven} #{eight} #{nine} #{ten}"
end
benchmark.report "#+ (<)" do
one + " " + two
end
benchmark.report "#+ (>)" do
one + " " + two + " " + three + " " + four + " " + five + " " + six + " " + seven + " " +
eight + " " + nine + " " + ten
end
# Mutation.
benchmark.report "#concat (<)" do
one.dup.concat two
end
# Mutation.
benchmark.report "#concat (>)" do
one.dup.concat two, three, four, five, six, seven, eight, nine, ten
end
# Mutation.
benchmark.report "#<< (<)" do
one.dup << two
end
# Mutation.
benchmark.report "#<< (>)" do
one.dup << two << three << four << five << six << seven << eight << nine << ten
end
benchmark.report "Array#join (<)" do
[one, two].join " "
end
benchmark.report "Array#join (>)" do
[one, two, three, four, five, six, seven, eight, nine, ten].join " "
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Implicit (<) 4.799M i/100ms
Implicit (>) 4.553M i/100ms
Interpolation (<) 1.758M i/100ms
Interpolation (>) 453.241k i/100ms
#+ (<) 1.306M i/100ms
#+ (>) 166.101k i/100ms
#concat (<) 523.312k i/100ms
#concat (>) 234.069k i/100ms
#<< (<) 556.835k i/100ms
#<< (>) 302.248k i/100ms
Array#join (<) 1.065M i/100ms
Array#join (>) 384.393k i/100ms
Calculating -------------------------------------
Implicit (<) 73.295M (± 0.1%) i/s (13.64 ns/i) - 369.501M in 5.041267s
Implicit (>) 73.267M (± 0.3%) i/s (13.65 ns/i) - 368.762M in 5.033156s
Interpolation (<) 18.250M (± 2.0%) i/s (54.79 ns/i) - 91.404M in 5.010379s
Interpolation (>) 4.844M (± 0.9%) i/s (206.44 ns/i) - 24.475M in 5.053113s
#+ (<) 13.587M (± 1.9%) i/s (73.60 ns/i) - 67.921M in 5.000883s
#+ (>) 1.544M (± 2.3%) i/s (647.82 ns/i) - 7.807M in 5.060098s
#concat (<) 5.635M (± 3.1%) i/s (177.45 ns/i) - 28.259M in 5.019545s
#concat (>) 2.375M (± 2.7%) i/s (421.10 ns/i) - 11.938M in 5.030584s
#<< (<) 5.943M (± 3.4%) i/s (168.27 ns/i) - 30.069M in 5.065748s
#<< (>) 3.099M (± 2.8%) i/s (322.66 ns/i) - 15.717M in 5.075307s
Array#join (<) 11.232M (± 0.9%) i/s (89.03 ns/i) - 56.421M in 5.023741s
Array#join (>) 4.172M (± 1.6%) i/s (239.70 ns/i) - 21.142M in 5.068889s
Comparison:
Implicit (<): 73295358.8 i/s
Implicit (>): 73267016.7 i/s - same-ish: difference falls within error
Interpolation (<): 18250066.2 i/s - 4.02x slower
#+ (<): 13586594.1 i/s - 5.39x slower
Array#join (<): 11231833.8 i/s - 6.53x slower
#<< (<): 5942722.8 i/s - 12.33x slower
#concat (<): 5635299.8 i/s - 13.01x slower
Interpolation (>): 4843906.9 i/s - 15.13x slower
Array#join (>): 4171886.7 i/s - 17.57x slower
#<< (>): 3099282.3 i/s - 23.65x slower
#concat (>): 2374759.3 i/s - 30.86x slower
#+ (>): 1543630.9 i/s - 47.48x slower
....
=== scripts/strings/matching
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
require "securerandom"
word = SecureRandom.alphanumeric 100
string_matcher = "a"
regex_matcher = /\Aa/
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("#match?") { word.match? regex_matcher }
benchmark.report("#=~") { word =~ regex_matcher }
benchmark.report("#start_with? (String)") { word.start_with? string_matcher }
benchmark.report("#start_with? (Regex)") { word.start_with? regex_matcher }
benchmark.report("#end_with?") { word.end_with? string_matcher }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#match? 2.495M i/100ms
#=~ 1.446M i/100ms
#start_with? (String)
3.037M i/100ms
#start_with? (Regex) 806.851k i/100ms
#end_with? 3.167M i/100ms
Calculating -------------------------------------
#match? 29.221M (± 0.1%) i/s (34.22 ns/i) - 147.203M in 5.037510s
#=~ 15.667M (± 7.1%) i/s (63.83 ns/i) - 78.073M in 5.023256s
#start_with? (String)
35.530M (± 0.4%) i/s (28.14 ns/i) - 179.183M in 5.043172s
#start_with? (Regex) 7.438M (±24.5%) i/s (134.44 ns/i) - 34.695M in 5.023176s
#end_with? 36.134M (± 0.2%) i/s (27.68 ns/i) - 183.713M in 5.084305s
Comparison:
#end_with?: 36133533.7 i/s
#start_with? (String): 35530349.2 i/s - 1.02x slower
#match?: 29221455.8 i/s - 1.24x slower
#=~: 15666854.2 i/s - 2.31x slower
#start_with? (Regex): 7438366.7 i/s - 4.86x slower
....
=== scripts/strings/split
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
require "securerandom"
words = Array.new(100_000) { SecureRandom.alphanumeric 10 }
delimiter = " "
text = words.join delimiter
pattern = /\Aa/
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "Without Block" do
text.split(delimiter).grep(pattern)
end
benchmark.report "With Block" do
selections = []
text.split(delimiter) { |word| selections << word if word.match? pattern }
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Without Block 16.000 i/100ms
With Block 14.000 i/100ms
Calculating -------------------------------------
Without Block 160.934 (± 1.9%) i/s (6.21 ms/i) - 816.000 in 5.071684s
With Block 147.259 (± 0.7%) i/s (6.79 ms/i) - 742.000 in 5.039222s
Comparison:
Without Block: 160.9 i/s
With Block: 147.3 i/s - 1.09x slower
....
=== scripts/strings/substrings
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
example = "example"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("#sub (string)") { example.sub "x", "b" }
benchmark.report("#sub (regex)") { example.sub(/x/, "b") }
benchmark.report("#gsub (string)") { example.gsub "x", "b" }
benchmark.report("#gsub (regex)") { example.gsub(/x/, "b") }
benchmark.report("#tr") { example.tr "x", "b" }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
#sub (string) 720.839k i/100ms
#sub (regex) 486.003k i/100ms
#gsub (string) 504.617k i/100ms
#gsub (regex) 264.917k i/100ms
#tr 1.303M i/100ms
Calculating -------------------------------------
#sub (string) 7.516M (± 0.8%) i/s (133.05 ns/i) - 38.204M in 5.083576s
#sub (regex) 5.268M (± 0.7%) i/s (189.83 ns/i) - 26.730M in 5.074524s
#gsub (string) 5.380M (± 0.6%) i/s (185.89 ns/i) - 27.249M in 5.065536s
#gsub (regex) 2.822M (± 0.8%) i/s (354.38 ns/i) - 14.306M in 5.069954s
#tr 13.969M (± 0.5%) i/s (71.59 ns/i) - 70.343M in 5.035839s
Comparison:
#tr: 13968882.9 i/s
#sub (string): 7515708.4 i/s - 1.86x slower
#gsub (string): 5379557.6 i/s - 2.60x slower
#sub (regex): 5267767.1 i/s - 2.65x slower
#gsub (regex): 2821821.0 i/s - 4.95x slower
....
=== scripts/thens
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report "standard" do
one, two = "one two".split
"#{one} + #{two} = #{one + two}"
end
benchmark.report "then" do
"one two".split.then { |one, two| "#{one} + #{two} = #{one + two}" }
end
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
standard 520.294k i/100ms
then 488.597k i/100ms
Calculating -------------------------------------
standard 5.408M (± 0.8%) i/s (184.93 ns/i) - 27.055M in 5.003534s
then 5.043M (± 0.7%) i/s (198.29 ns/i) - 25.407M in 5.038137s
Comparison:
standard: 5407583.0 i/s
then: 5043181.2 i/s - 1.07x slower
....
=== scripts/values/inheritance
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
PlotStruct = Struct.new :x, :y
class PlotSubclass < Struct.new :x, :y
end
struct = -> { PlotStruct[x: 1, y: 2] }
subclass = -> { PlotSubclass[x: 1, y: 2] }
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Struct") { struct.call }
benchmark.report("Subclass") { subclass.call }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Struct 538.804k i/100ms
Subclass 518.538k i/100ms
Calculating -------------------------------------
Struct 5.886M (± 1.3%) i/s (169.90 ns/i) - 29.634M in 5.035664s
Subclass 5.620M (± 1.0%) i/s (177.92 ns/i) - 28.520M in 5.074817s
Comparison:
Struct: 5885853.0 i/s
Subclass: 5620422.5 i/s - 1.05x slower
....
=== scripts/values/initialization
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
gem "dry-struct"
end
Warning[:performance] = false
require "ostruct"
DataDefault = Data.define :a, :b, :c, :d, :e
DataCustom = Data.define :a, :b, :c, :d, :e do
def initialize a: 1, b: 2, c: 3, d: 4, e: 5
super
end
end
StructDefault = Struct.new :a, :b, :c, :d, :e
StructCustom = Struct.new :a, :b, :c, :d, :e do
def initialize a: 1, b: 2, c: 3, d: 4, e: 5
super
end
end
module Types
include Dry.Types
end
DryExample = Class.new Dry::Struct do
attribute :a, Types::Strict::Integer
attribute :b, Types::Strict::Integer
attribute :c, Types::Strict::Integer
attribute :d, Types::Strict::Integer
attribute :e, Types::Strict::Integer
end
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Data (positional)") { DataDefault[1, 2, 3, 4, 5] }
benchmark.report("Data (keyword)") { DataDefault[a: 1, b: 2, c: 3, d: 4, e: 5] }
benchmark.report("Data (custom)") { DataCustom.new }
benchmark.report("Struct (positional)") { StructDefault[1, 2, 3, 4, 5] }
benchmark.report("Struct (keyword)") { StructDefault[a: 1, b: 2, c: 3, d: 4, e: 5] }
benchmark.report("Struct (custom)") { StructCustom.new }
benchmark.report("OpenStruct") { OpenStruct.new a: 1, b: 2, c: 3, d: 4, e: 5 }
benchmark.report("Dry Struct") { DryExample[a: 1, b: 2, c: 3, d: 4, e: 5] }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Data (positional) 353.466k i/100ms
Data (keyword) 350.442k i/100ms
Data (custom) 318.060k i/100ms
Struct (positional) 1.131M i/100ms
Struct (keyword) 362.009k i/100ms
Struct (custom) 352.839k i/100ms
OpenStruct 11.114k i/100ms
Dry Struct 124.525k i/100ms
Calculating -------------------------------------
Data (positional) 3.719M (± 1.1%) i/s (268.90 ns/i) - 18.734M in 5.038109s
Data (keyword) 3.874M (± 2.0%) i/s (258.16 ns/i) - 19.625M in 5.068537s
Data (custom) 3.358M (± 1.7%) i/s (297.78 ns/i) - 16.857M in 5.021195s
Struct (positional) 12.121M (± 1.8%) i/s (82.50 ns/i) - 61.063M in 5.039431s
Struct (keyword) 3.805M (± 3.9%) i/s (262.83 ns/i) - 19.186M in 5.050768s
Struct (custom) 3.676M (± 1.6%) i/s (272.02 ns/i) - 18.700M in 5.088300s
OpenStruct 109.497k (± 2.8%) i/s (9.13 μs/i) - 555.700k in 5.079350s
Dry Struct 1.306M (± 0.9%) i/s (765.65 ns/i) - 6.600M in 5.053588s
Comparison:
Struct (positional): 12121050.5 i/s
Data (keyword): 3873563.1 i/s - 3.13x slower
Struct (keyword): 3804720.3 i/s - 3.19x slower
Data (positional): 3718834.2 i/s - 3.26x slower
Struct (custom): 3676182.7 i/s - 3.30x slower
Data (custom): 3358180.2 i/s - 3.61x slower
Dry Struct: 1306074.7 i/s - 9.28x slower
OpenStruct: 109496.8 i/s - 110.70x slower
ℹ️ `Data` is fastest when members are small (like three or less) but performance degrades when more members are added (like five or more). This is because `Data` always initializes with a `Hash` which is not the case with a `Struct`. Additionally, passing keyword arguments to/from Ruby to Ruby is optimized while to/from Ruby/C is not.
....
=== scripts/values/reading
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
gem "dry-struct"
end
require "ostruct"
DataExample = Data.define :to, :from
StructExample = Struct.new :to, :from
module Types
include Dry.Types
end
DryExample = Class.new Dry::Struct do
attribute :to, Types::Strict::String
attribute :from, Types::Strict::String
end
data = DataExample[to: "Rick", from: "Morty"]
struct = StructExample[to: "Rick", from: "Morty"]
open_struct = OpenStruct.new to: "Rick", from: "Morty"
dry_struct = DryExample[to: "Rick", from: "Morty"]
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Data") { data.to }
benchmark.report("Struct") { struct.to }
benchmark.report("OpenStruct") { open_struct.to }
benchmark.report("Dry Struct") { dry_struct.to }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Data 4.138M i/100ms
Struct 4.402M i/100ms
OpenStruct 2.431M i/100ms
Dry Struct 3.723M i/100ms
Calculating -------------------------------------
Data 67.301M (± 2.9%) i/s (14.86 ns/i) - 339.284M in 5.046842s
Struct 67.277M (± 0.4%) i/s (14.86 ns/i) - 338.976M in 5.038558s
OpenStruct 31.752M (± 0.1%) i/s (31.49 ns/i) - 160.441M in 5.052954s
Dry Struct 46.533M (± 0.2%) i/s (21.49 ns/i) - 234.527M in 5.040063s
Comparison:
Data: 67301380.0 i/s
Struct: 67277416.8 i/s - same-ish: difference falls within error
Dry Struct: 46532814.0 i/s - 1.45x slower
OpenStruct: 31751956.0 i/s - 2.12x slower
....
=== scripts/values/writing
.*Source*
[%collapsible]
====
[source,ruby]
----
#! /usr/bin/env ruby
# frozen_string_literal: true
require "bundler/inline"
gemfile true do
source "https://rubygems.org"
gem "benchmark-ips"
end
require "ostruct"
DataExample = Data.define :to, :from
StructExample = Struct.new :to, :from
data = DataExample[to: "Rick", from: "Morty"]
struct = StructExample[to: "Rick", from: "Morty"]
open_struct = OpenStruct.new to: "Rick", from: "Morty"
Benchmark.ips do |benchmark|
benchmark.config time: 5, warmup: 2
benchmark.report("Data") { data.with from: "Summer" }
benchmark.report("Struct") { struct.from = "Summer" }
benchmark.report("OpenStruct") { open_struct.from = "Summer" }
benchmark.compare!
end
----
====
*Benchmark*
....
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin24.2.0]
Warming up --------------------------------------
Data 365.681k i/100ms
Struct 4.017M i/100ms
OpenStruct 1.970M i/100ms
Calculating -------------------------------------
Data 3.818M (± 1.0%) i/s (261.92 ns/i) - 19.381M in 5.076819s
Struct 53.012M (± 0.3%) i/s (18.86 ns/i) - 265.090M in 5.000654s
OpenStruct 24.920M (± 0.2%) i/s (40.13 ns/i) - 126.093M in 5.059884s
Comparison:
Struct: 53011585.3 i/s
OpenStruct: 24920314.7 i/s - 2.13x slower
Data: 3817956.9 i/s - 13.88x slower
....
== Development
To contribute, run:
[source,bash]
----
git clone https://github.com/bkuhlmann/benchmarks.git
cd benchmarks
bin/setup
----
To render documentation for all benchmark scripts, run:
[source,bash]
----
bin/render
----
This is the same script used to update the documentation within this README.
== Tests
To test, run:
[source,bash]
----
bin/rake
----
== link:https://alchemists.io/policies/license[License]
== link:https://alchemists.io/policies/security[Security]
== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]
== link:https://alchemists.io/policies/contributions[Contributions]
== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]
== link:https://alchemists.io/projects/benchmarks/versions[Versions]
== link:https://alchemists.io/community[Community]
== Credits
* Built with link:https://alchemists.io/projects/rubysmith[Rubysmith].
* Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].
Owner
- Name: Brooke Kuhlmann
- Login: bkuhlmann
- Kind: user
- Location: Boulder, CO USA
- Company: Alchemists
- Website: https://alchemists.io
- Repositories: 56
- Profile: https://github.com/bkuhlmann
Quality over quantity.
Citation (CITATION.cff)
cff-version: 1.2.0
message: Please use the following metadata when citing this project in your work.
title: Benchmarks
abstract: A collection of micro benchmarks.
version: 5.4.0
license: Hippocratic-2.1
date-released: 2025-07-15
authors:
- family-names: Kuhlmann
given-names: Brooke
affiliation: Alchemists
orcid: https://orcid.org/0000-0002-5810-6268
keywords:
- ruby
- benchmarks
- performance
repository-code: https://github.com/bkuhlmann/benchmarks
repository-artifact: https://alchemists.io/projects/benchmarks
url: https://alchemists.io/projects/benchmarks
GitHub Events
Total
- Watch event: 1
- Delete event: 229
- Push event: 40
- Create event: 65
Last Year
- Watch event: 1
- Delete event: 229
- Push event: 40
- Create event: 65
Issues and Pull Requests
Last synced: 10 months ago
All Time
- Total issues: 0
- Total pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Total issue authors: 0
- Total pull request authors: 0
- Average comments per issue: 0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Past Year
- Issues: 0
- Pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Issue authors: 0
- Pull request authors: 0
- Average comments per issue: 0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Top Authors
Issue Authors
Pull Request Authors
Top Labels
Issue Labels
Pull Request Labels
Dependencies
Gemfile
rubygems
- amazing_print ~> 1.4 development
- caliber ~> 0.25 development
- debug ~> 1.7 development
- git-lint ~> 5.0 development
- guard-rspec ~> 4.7 development
- rake ~> 13.0 development
- reek ~> 6.1 development
- rspec ~> 3.12 development
- simplecov ~> 0.22 development
- refinements ~> 10.0