Skip to content

Commit 1cd777e

Browse files
authored
Merge pull request #2 from lucianghinda/lg/add-tests-for-data-define-positional
Add comparisons for Data.define for creating or accessing attributes
2 parents f61010e + a247679 commit 1cd777e

File tree

6 files changed

+283
-5
lines changed

6 files changed

+283
-5
lines changed

README.md

Lines changed: 134 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
# Micro Benchmarks on Value Object options in Ruby
22

3-
A series of micro benchmarks about Data.define vs Struct vs OpenStruct in #Ruby.
4-
53
This is executed with defaults, no extra settings added.
64

7-
The tests are focused on using keyword arguments. The results might be different when using positional arguments.
8-
95
## How to run the benchmarks
106

117
```bash
128
bundle install
139
bundle exec ruby <benchmark>
1410
```
1511

16-
## Results on my machine
12+
## Machine use to run the benchmarks
1713

1814
I run the following benchmarks on my machine:
1915

@@ -22,6 +18,12 @@ I run the following benchmarks on my machine:
2218
- Running Mac OS 14.4 (23E214)
2319
- Ruby 3.3.0
2420

21+
## Comparing Data.define with Struct and OpenStruct
22+
23+
Comparing Data.define with Struct and OpenStruct.
24+
25+
The benchmark is focused on benchmarking the keyword arguments.
26+
2527
### Creating Values
2628

2729
#### Benchmark with `bmbm`
@@ -128,3 +130,130 @@ Comparison:
128130
Struct: 28419.6 i/s - same-ish: difference falls within error
129131
OpenStruct: 13474.6 i/s - 2.13x slower
130132
```
133+
134+
## Comparing Data.define
135+
136+
### Comparing multiple ways to create a new object
137+
138+
#### Benchmark with `bmbm`
139+
140+
This benchmark is run with Ruby default benchmark using `bmbm`
141+
142+
```bash
143+
Comparing ways to instantiate a Data.define object - Benchmark with bmbm
144+
Rehearsal --------------------------------------------------------
145+
Keyword arguments 0.000025 0.000000 0.000025 ( 0.000025)
146+
Positional arguments 0.000058 0.000000 0.000058 ( 0.000059)
147+
Constructor method 0.000053 0.000000 0.000053 ( 0.000054)
148+
Constructor keywords 0.000029 0.000000 0.000029 ( 0.000029)
149+
----------------------------------------------- total: 0.000165sec
150+
151+
user system total real
152+
Keyword arguments 0.000023 0.000001 0.000024 ( 0.000023)
153+
Positional arguments 0.000039 0.000000 0.000039 ( 0.000039)
154+
Constructor method 0.000046 0.000000 0.000046 ( 0.000046)
155+
Constructor keywords 0.000023 0.000000 0.000023 ( 0.000023)
156+
```
157+
158+
#### Benchmarking with `ips`
159+
160+
This benchmark is run with `benchmark-ips` gem.
161+
162+
```bash
163+
Comparing ways to instantiate a Data.define object - Benchmark with ips
164+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
165+
Warming up --------------------------------------
166+
Keyword arguments 5.345k i/100ms
167+
Positional arguments 2.692k i/100ms
168+
Constructor method 2.663k i/100ms
169+
Constructor keywords 5.354k i/100ms
170+
Calculating -------------------------------------
171+
Keyword arguments 52.390k (± 1.9%) i/s - 261.905k in 5.000971s
172+
Positional arguments 26.162k (± 1.1%) i/s - 131.908k in 5.042607s
173+
Constructor method 26.149k (± 0.8%) i/s - 133.150k in 5.092403s
174+
Constructor keywords 51.813k (± 1.6%) i/s - 262.346k in 5.064698s
175+
176+
Comparison:
177+
Keyword arguments: 52390.1 i/s
178+
Constructor keywords: 51812.7 i/s - same-ish: difference falls within error
179+
Positional arguments: 26162.3 i/s - 2.00x slower
180+
Constructor method: 26148.6 i/s - 2.00x slower
181+
```
182+
183+
### Benchmarking with `memory`
184+
185+
This benchmark is run with `benchmark-memory` gem.
186+
187+
This test is probably unnecessary cause in the end it creates the same thing.
188+
189+
```bash
190+
Comparing ways to instantiate a Data.define object - Benchmark with memory
191+
Calculating -------------------------------------
192+
Keyword arguments 36.792k memsize ( 0.000 retained)
193+
2.000 objects ( 0.000 retained)
194+
0.000 strings ( 0.000 retained)
195+
Positional arguments 36.792k memsize ( 0.000 retained)
196+
2.000 objects ( 0.000 retained)
197+
0.000 strings ( 0.000 retained)
198+
Constructor method 36.792k memsize ( 0.000 retained)
199+
2.000 objects ( 0.000 retained)
200+
0.000 strings ( 0.000 retained)
201+
Constructor keywords 36.792k memsize ( 0.000 retained)
202+
2.000 objects ( 0.000 retained)
203+
0.000 strings ( 0.000 retained)
204+
205+
Comparison:
206+
Keyword arguments: 36792 allocated
207+
Positional arguments: 36792 allocated - same
208+
Constructor method: 36792 allocated - same
209+
Constructor keywords: 36792 allocated - same
210+
```
211+
212+
### Comparing accessing data from objects created differently
213+
214+
There is no difference in accessing attributes depending on how the object was created.
215+
216+
#### Benchmark with `bmbm`
217+
218+
This benchmark is run with Ruby default benchmark using `bmbm`
219+
220+
```bash
221+
Comparing accessing data for Data.define object - Benchmark with bmbm
222+
Rehearsal --------------------------------------------------------
223+
Keyword arguments 0.000072 0.000002 0.000074 ( 0.000074)
224+
Positional arguments 0.000046 0.000001 0.000047 ( 0.000047)
225+
Constructor method 0.000047 0.000000 0.000047 ( 0.000047)
226+
Constructor keywords 0.000047 0.000001 0.000048 ( 0.000048)
227+
----------------------------------------------- total: 0.000216sec
228+
229+
user system total real
230+
Keyword arguments 0.000048 0.000001 0.000049 ( 0.000048)
231+
Positional arguments 0.000047 0.000000 0.000047 ( 0.000047)
232+
Constructor method 0.000047 0.000000 0.000047 ( 0.000048)
233+
Constructor keywords 0.000047 0.000001 0.000048 ( 0.000047)
234+
```
235+
236+
#### Benchmark with `ips`
237+
238+
This benchmark is run with `benchmark-ips` gem.
239+
240+
```bash
241+
Comparing accessing data for Data.define object - Benchmark with bmbm
242+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
243+
Warming up --------------------------------------
244+
Keyword arguments 2.669k i/100ms
245+
Positional arguments 2.657k i/100ms
246+
Constructor method 2.685k i/100ms
247+
Constructor keywords 2.690k i/100ms
248+
Calculating -------------------------------------
249+
Keyword arguments 26.925k (± 0.5%) i/s - 136.119k in 5.055637s
250+
Positional arguments 26.835k (± 0.4%) i/s - 135.507k in 5.049741s
251+
Constructor method 26.895k (± 0.3%) i/s - 136.935k in 5.091470s
252+
Constructor keywords 26.794k (± 0.4%) i/s - 134.500k in 5.019767s
253+
254+
Comparison:
255+
Keyword arguments: 26924.8 i/s
256+
Constructor method: 26895.3 i/s - same-ish: difference falls within error
257+
Positional arguments: 26834.9 i/s - same-ish: difference falls within error
258+
Constructor keywords: 26794.4 i/s - same-ish: difference falls within error
259+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
require 'benchmark'
2+
3+
keys = 1000.times.map { |i| "key#{i}".to_sym }
4+
values = 1000.times.map { |i| "value#{i}" }
5+
keys_and_values = Hash[keys.zip(values)]
6+
7+
DataDefine = Data.define(*keys)
8+
keyword_args = DataDefine.new(**keys_and_values)
9+
positional_args = DataDefine.new(*values)
10+
constructor_method = DataDefine[*values]
11+
constructor_with_keyword_args = DataDefine[**keys_and_values]
12+
13+
puts "Comparing accessing data for Data.define object - Benchmark with bmbm"
14+
15+
Benchmark.bmbm do |x|
16+
x.report("Keyword arguments") do
17+
keys.each { keyword_args.send(_1) }
18+
end
19+
20+
x.report("Positional arguments") do
21+
keys.each { positional_args.send(_1) }
22+
end
23+
24+
x.report("Constructor method") do
25+
keys.each { constructor_method.send(_1) }
26+
end
27+
28+
x.report("Constructor keywords") do
29+
keys.each { constructor_with_keyword_args.send(_1) }
30+
end
31+
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'benchmark/ips'
2+
3+
keys = 1000.times.map { |i| "key#{i}".to_sym }
4+
values = 1000.times.map { |i| "value#{i}" }
5+
keys_and_values = Hash[keys.zip(values)]
6+
7+
DataDefine = Data.define(*keys)
8+
keyword_args = DataDefine.new(**keys_and_values)
9+
positional_args = DataDefine.new(*values)
10+
constructor_method = DataDefine[*values]
11+
constructor_with_keyword_args = DataDefine[**keys_and_values]
12+
13+
puts "Comparing accessing data for Data.define object - Benchmark with bmbm"
14+
15+
Benchmark.ips do |x|
16+
x.report("Keyword arguments") do
17+
keys.each { keyword_args.send(_1) }
18+
end
19+
20+
x.report("Positional arguments") do
21+
keys.each { positional_args.send(_1) }
22+
end
23+
24+
x.report("Constructor method") do
25+
keys.each { constructor_method.send(_1) }
26+
end
27+
28+
x.report("Constructor keywords") do
29+
keys.each { constructor_with_keyword_args.send(_1) }
30+
end
31+
32+
x.compare!
33+
end

data-define/creating_values/bmbm.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require 'benchmark'
2+
3+
keys = 1000.times.map { |i| "key#{i}".to_sym }
4+
values = 1000.times.map { |i| "value#{i}" }
5+
keys_and_values = Hash[keys.zip(values)]
6+
7+
DataDefine = Data.define(*keys)
8+
9+
puts "Comparing ways to instantiate a Data.define object - Benchmark with bmbm"
10+
11+
Benchmark.bmbm do |x|
12+
x.report("Keyword arguments") do
13+
DataDefine.new(**keys_and_values)
14+
end
15+
16+
x.report("Positional arguments") do
17+
DataDefine.new(*values)
18+
end
19+
20+
x.report("Constructor method") do
21+
DataDefine[*values]
22+
end
23+
24+
x.report("Constructor keywords") do
25+
DataDefine[**keys_and_values]
26+
end
27+
end

data-define/creating_values/ips.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require 'benchmark/ips'
2+
3+
keys = 1000.times.map { |i| "key#{i}".to_sym }
4+
values = 1000.times.map { |i| "value#{i}" }
5+
keys_and_values = Hash[keys.zip(values)]
6+
7+
DataDefine = Data.define(*keys)
8+
9+
puts "Comparing ways to instantiate a Data.define object - Benchmark with ips"
10+
11+
Benchmark.ips do |x|
12+
x.report("Keyword arguments") do
13+
DataDefine.new(**keys_and_values)
14+
end
15+
16+
x.report("Positional arguments") do
17+
DataDefine.new(*values)
18+
end
19+
20+
x.report("Constructor method") do
21+
DataDefine[*values]
22+
end
23+
24+
x.report("Constructor keywords") do
25+
DataDefine[**keys_and_values]
26+
end
27+
28+
x.compare!
29+
end

data-define/creating_values/memory.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require 'benchmark/memory'
2+
3+
keys = 1000.times.map { |i| "key#{i}".to_sym }
4+
values = 1000.times.map { |i| "value#{i}" }
5+
keys_and_values = Hash[keys.zip(values)]
6+
7+
DataDefine = Data.define(*keys)
8+
9+
puts "Comparing ways to instantiate a Data.define object - Benchmark with memory"
10+
11+
Benchmark.memory do |x|
12+
x.report("Keyword arguments") do
13+
DataDefine.new(**keys_and_values)
14+
end
15+
16+
x.report("Positional arguments") do
17+
DataDefine.new(*values)
18+
end
19+
20+
x.report("Constructor method") do
21+
DataDefine[*values]
22+
end
23+
24+
x.report("Constructor keywords") do
25+
DataDefine[**keys_and_values]
26+
end
27+
28+
x.compare!
29+
end

0 commit comments

Comments
 (0)