Skip to content

Instantly share code, notes, and snippets.

@kputnam
Last active April 13, 2022 23:50
Show Gist options
  • Save kputnam/015f6287dea48471baea9f419bbe274d to your computer and use it in GitHub Desktop.
Save kputnam/015f6287dea48471baea9f419bbe274d to your computer and use it in GitHub Desktop.
Object#cons and Object#snoc benchmarks
#!/usr/bin/env ruby
require "pp"
require "benchmark/ips"
require "memory_profiler"
GC.disable
def mem(label, &block)
result = MemoryProfiler::Reporter.report(&block)
print label.ljust(30); pp result.allocated_memory_by_class
end
def cons_a(n, xs); i = 0; while i < n; i += 1; [0] + xs ;end;end
def cons_b(n, xs); i = 0; while i < n; i += 1; [0, *xs] ;end;end
def cons_c(n, xs); i = 0; while i < n; i += 1; [0].push(*xs) ;end;end
def cons_d(n, xs); i = 0; while i < n; i += 1; xs.dup.unshift(0) ;end;end
def snoc_a(n, xs); i = 0; while i < n; i += 1; xs + [0] ;end;end
def snoc_b(n, xs); i = 0; while i < n; i += 1; [*xs, 0] ;end;end
def snoc_c(n, xs); i = 0; while i < n; i += 1; xs.dup.push(0) ;end;end
def snoc_d(n, xs); i = 0; while i < n; i += 1; [0, *xs.reverse].reverse ;end;end
XS = [1, 2, 3, 4].freeze
puts "CONS #{"="*73}"
mem("[0] + xs") { cons_a(500_000, XS) }
mem("[0, *xs]") { cons_b(500_000, XS) }
mem("[0].push(*xs)") { cons_c(500_000, XS) }
mem("xs.dup.unshift(0)") { cons_d(500_000, XS) }
Benchmark.ips do |x|
x.report("[0] + xs") {|n| cons_a(n, XS) }
x.report("[0, *xs]") {|n| cons_b(n, XS) }
x.report("[0].push(*xs)") {|n| cons_c(n, XS) }
x.report("xs.dup.unshift(0)") {|n| cons_d(n, XS) }
x.compare!
end
puts "SNOC #{"="*73}"
mem("xs + [5]") { snoc_a(500_000, XS) }
mem("[*xs, 5]") { snoc_b(500_000, XS) }
mem("xs.dup.push(5)") { snoc_c(500_000, XS) }
mem("[5, *xs.reverse].reverse") { snoc_d(500_000, XS) }
Benchmark.ips do |x|
x.report("xs + [5]") {|n| snoc_a(n, XS) }
x.report("[*xs, 5]") {|n| snoc_b(n, XS) }
x.report("xs.dup.push(5)") {|n| snoc_c(n, XS) }
x.report("[5, *xs.reverse].reverse") {|n| snoc_d(n, XS) }
x.compare!
end
mem = Integer(`ps -o rss= -p #{Process.pid}`) * 0.001
puts "Process: %0.2d MiB" % mem
CONS =========================================================================
[0] + xs [{:data=>"Array", :count=>60000000}]
[0, *xs] [{:data=>"Array", :count=>20000000}]
[0].push(*xs) [{:data=>"Array", :count=>104000000}]
xs.dup.unshift(0) [{:data=>"Array", :count=>104000000}]
Warming up --------------------------------------
[0] + xs 158.357k i/100ms
[0, *xs] 249.760k i/100ms
[0].push(*xs) 144.966k i/100ms
xs.dup.unshift(0) 105.764k i/100ms
Calculating -------------------------------------
[0] + xs 4.001M (± 6.5%) i/s - 19.953M in 5.012735s
[0, *xs] 20.164M (± 3.4%) i/s - 100.903M in 5.010392s
[0].push(*xs) 3.402M (± 6.3%) i/s - 17.106M in 5.048869s
xs.dup.unshift(0) 1.808M (± 4.0%) i/s - 9.096M in 5.038773s
Comparison:
[0, *xs]: 20163644.4 i/s
[0] + xs: 4000698.8 i/s - 5.04x slower
[0].push(*xs): 3401973.3 i/s - 5.93x slower
xs.dup.unshift(0): 1808018.4 i/s - 11.15x slower
SNOC =========================================================================
xs + [5] [{:data=>"Array", :count=>60000000}]
[*xs, 5] [{:data=>"Array", :count=>36000000}]
xs.dup.push(5) [{:data=>"Array", :count=>104000000}]
[5, *xs.reverse].reverse [{:data=>"Array", :count=>200000000}]
Warming up --------------------------------------
xs + [5] 165.681k i/100ms
[*xs, 5] 177.168k i/100ms
xs.dup.push(5) 107.331k i/100ms
[5, *xs.reverse].reverse
88.039k i/100ms
Calculating -------------------------------------
xs + [5] 3.923M (± 4.0%) i/s - 19.716M in 5.034287s
[*xs, 5] 4.486M (± 4.9%) i/s - 22.500M in 5.028227s
xs.dup.push(5) 1.803M (± 4.4%) i/s - 9.016M in 5.008696s
[5, *xs.reverse].reverse
1.250M (±17.9%) i/s - 5.723M in 5.018827s
Comparison:
[*xs, 5]: 4486418.3 i/s
xs + [5]: 3922868.0 i/s - 1.14x slower
xs.dup.push(5): 1803477.6 i/s - 2.49x slower
[5, *xs.reverse].reverse: 1250223.3 i/s - 3.59x slower
Process: 177 MiB
CONS =========================================================================
[0] + xs [{:data=>"Array", :count=>60000000}]
[0, *xs] [{:data=>"Array", :count=>20000000}]
[0].push(*xs) [{:data=>"Array", :count=>104000000}]
xs.dup.unshift(0) [{:data=>"Array", :count=>104000000}]
Warming up --------------------------------------
[0] + xs 167.782k i/100ms
[0, *xs] 267.276k i/100ms
[0].push(*xs) 154.735k i/100ms
xs.dup.unshift(0) 100.309k i/100ms
Calculating -------------------------------------
[0] + xs 3.817M (±19.3%) i/s - 18.120M in 5.024482s
[0, *xs] 21.515M (± 7.8%) i/s - 106.910M in 5.005655s
[0].push(*xs) 3.306M (±14.3%) i/s - 16.092M in 5.004029s
xs.dup.unshift(0) 1.687M (± 8.8%) i/s - 8.426M in 5.035796s
Comparison:
[0, *xs]: 21515378.8 i/s
[0] + xs: 3817363.5 i/s - 5.64x slower
[0].push(*xs): 3305575.6 i/s - 6.51x slower
xs.dup.unshift(0): 1686959.4 i/s - 12.75x slower
SNOC =========================================================================
xs + [5] [{:data=>"Array", :count=>60000000}]
[*xs, 5] [{:data=>"Array", :count=>36000000}]
xs.dup.push(5) [{:data=>"Array", :count=>104000000}]
[5, *xs.reverse].reverse [{:data=>"Array", :count=>200000000}]
Warming up --------------------------------------
xs + [5] 172.941k i/100ms
[*xs, 5] 163.911k i/100ms
xs.dup.push(5) 103.533k i/100ms
[5, *xs.reverse].reverse
92.412k i/100ms
Calculating -------------------------------------
xs + [5] 4.185M (± 6.3%) i/s - 20.926M in 5.020849s
[*xs, 5] 4.679M (± 6.6%) i/s - 23.275M in 5.000333s
xs.dup.push(5) 1.904M (± 4.9%) i/s - 9.525M in 5.015530s
[5, *xs.reverse].reverse
1.411M (± 4.2%) i/s - 7.116M in 5.051060s
Comparison:
[*xs, 5]: 4678600.6 i/s
xs + [5]: 4184616.8 i/s - same-ish: difference falls within error
xs.dup.push(5): 1903741.9 i/s - 2.46x slower
[5, *xs.reverse].reverse: 1411382.4 i/s - 3.31x slower
Process: 229 MiB
CONS =========================================================================
[0] + xs [{:data=>"Array", :count=>60000000}]
[0, *xs] [{:data=>"Array", :count=>20000000}]
[0].push(*xs) [{:data=>"Array", :count=>104000000}]
xs.dup.unshift(0) [{:data=>"Array", :count=>104000000}]
Warming up --------------------------------------
[0] + xs 182.307k i/100ms
[0, *xs] 288.519k i/100ms
[0].push(*xs) 147.349k i/100ms
xs.dup.unshift(0) 113.528k i/100ms
Calculating -------------------------------------
[0] + xs 4.295M (± 8.4%) i/s - 21.512M in 5.031081s
[0, *xs] 23.616M (± 6.3%) i/s - 117.716M in 5.005438s
[0].push(*xs) 3.833M (±18.4%) i/s - 18.271M in 5.000693s
xs.dup.unshift(0) 1.909M (± 5.3%) i/s - 9.536M in 5.009102s
Comparison:
[0, *xs]: 23616219.6 i/s
[0] + xs: 4294929.8 i/s - 5.50x slower
[0].push(*xs): 3832976.0 i/s - 6.16x slower
xs.dup.unshift(0): 1908544.6 i/s - 12.37x slower
SNOC =========================================================================
xs + [5] [{:data=>"Array", :count=>60000000}]
[*xs, 5] [{:data=>"Array", :count=>36000000}]
xs.dup.push(5) [{:data=>"Array", :count=>104000000}]
[5, *xs.reverse].reverse [{:data=>"Array", :count=>200000000}]
Warming up --------------------------------------
xs + [5] 191.852k i/100ms
[*xs, 5] 205.475k i/100ms
xs.dup.push(5) 107.392k i/100ms
[5, *xs.reverse].reverse
94.345k i/100ms
Calculating -------------------------------------
xs + [5] 4.296M (±14.4%) i/s - 21.104M in 5.005134s
[*xs, 5] 5.226M (±21.5%) i/s - 25.479M in 5.038493s
xs.dup.push(5) 1.976M (±22.4%) i/s - 8.484M in 5.041697s
[5, *xs.reverse].reverse
1.415M (±19.7%) i/s - 6.887M in 5.020408s
Comparison:
[*xs, 5]: 5226393.4 i/s
xs + [5]: 4295635.6 i/s - same-ish: difference falls within error
xs.dup.push(5): 1976485.8 i/s - 2.64x slower
[5, *xs.reverse].reverse: 1414967.1 i/s - 3.69x slower
Process: 916 MiB
CONS =========================================================================
[0] + xs [{:data=>"Array", :count=>60000000}]
[0, *xs] []
[0].push(*xs) [{:data=>"Array", :count=>104000000}]
xs.dup.unshift(0) [{:data=>"Array", :count=>104000000}]
Warming up --------------------------------------
[0] + xs 178.548k i/100ms
[0, *xs] 313.357k i/100ms
[0].push(*xs) 170.827k i/100ms
xs.dup.unshift(0) 116.468k i/100ms
Calculating -------------------------------------
[0] + xs 4.276M (± 5.1%) i/s - 21.426M in 5.026476s
[0, *xs] 45.619M (± 4.3%) i/s - 227.497M in 4.999133s
[0].push(*xs) 3.712M (± 7.0%) i/s - 18.620M in 5.045213s
xs.dup.unshift(0) 1.946M (± 2.6%) i/s - 9.783M in 5.030577s
Comparison:
[0, *xs]: 45619256.8 i/s
[0] + xs: 4276348.2 i/s - 10.67x slower
[0].push(*xs): 3711830.7 i/s - 12.29x slower
xs.dup.unshift(0): 1946086.7 i/s - 23.44x slower
SNOC =========================================================================
xs + [5] [{:data=>"Array", :count=>60000000}]
[*xs, 5] [{:data=>"Array", :count=>36000000}]
xs.dup.push(5) [{:data=>"Array", :count=>104000000}]
[5, *xs.reverse].reverse [{:data=>"Array", :count=>200000000}]
Warming up --------------------------------------
xs + [5] 179.656k i/100ms
[*xs, 5] 192.123k i/100ms
xs.dup.push(5) 120.012k i/100ms
[5, *xs.reverse].reverse
99.089k i/100ms
Calculating -------------------------------------
xs + [5] 4.240M (± 5.7%) i/s - 21.199M in 5.020647s
[*xs, 5] 4.862M (± 5.3%) i/s - 24.400M in 5.035657s
xs.dup.push(5) 1.928M (± 4.6%) i/s - 9.721M in 5.052745s
[5, *xs.reverse].reverse
1.499M (± 3.7%) i/s - 7.531M in 5.032273s
Comparison:
[*xs, 5]: 4861939.7 i/s
xs + [5]: 4239664.7 i/s - 1.15x slower
xs.dup.push(5): 1928168.5 i/s - 2.52x slower
[5, *xs.reverse].reverse: 1498704.3 i/s - 3.24x slower
Process: 352 MiB
CONS =========================================================================
[0] + xs [{:data=>"Array", :count=>60000000}]
[0, *xs] []
[0].push(*xs) [{:data=>"Array", :count=>104000000}]
xs.dup.unshift(0) [{:data=>"Array", :count=>104000000}]
Warming up --------------------------------------
[0] + xs 299.980k i/100ms
[0, *xs] 374.370k i/100ms
[0].push(*xs) 290.385k i/100ms
xs.dup.unshift(0) 200.042k i/100ms
Calculating -------------------------------------
[0] + xs 13.409M (±10.8%) i/s - 66.296M in 5.020000s
[0, *xs] 54.612M (± 5.7%) i/s - 271.793M in 4.999686s
[0].push(*xs) 12.676M (± 4.8%) i/s - 63.304M in 5.007482s
xs.dup.unshift(0) 5.057M (± 2.6%) i/s - 25.405M in 5.027011s
Comparison:
[0, *xs]: 54611596.6 i/s
[0] + xs: 13408678.7 i/s - 4.07x slower
[0].push(*xs): 12675808.1 i/s - 4.31x slower
xs.dup.unshift(0): 5057342.5 i/s - 10.80x slower
SNOC =========================================================================
xs + [5] [{:data=>"Array", :count=>60000000}]
[*xs, 5] [{:data=>"Array", :count=>36000000}]
xs.dup.push(5) [{:data=>"Array", :count=>104000000}]
[5, *xs.reverse].reverse [{:data=>"Array", :count=>200000000}]
Warming up --------------------------------------
xs + [5] 242.832k i/100ms
[*xs, 5] 332.280k i/100ms
xs.dup.push(5) 210.093k i/100ms
[5, *xs.reverse].reverse
218.821k i/100ms
Calculating -------------------------------------
xs + [5] 14.651M (± 2.7%) i/s - 73.335M in 5.010120s
[*xs, 5] 21.410M (± 3.2%) i/s - 106.994M in 5.003528s
xs.dup.push(5) 5.155M (± 2.4%) i/s - 25.841M in 5.016489s
[5, *xs.reverse].reverse
5.517M (± 3.2%) i/s - 27.571M in 5.003341s
Comparison:
[*xs, 5]: 21409550.7 i/s
xs + [5]: 14651002.6 i/s - 1.46x slower
[5, *xs.reverse].reverse: 5516899.0 i/s - 3.88x slower
xs.dup.push(5): 5154712.4 i/s - 4.15x slower
Process: 388 MiB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment