-
-
Save larskanis/c1ef84c3e058e819786f5fd20bc7c207 to your computer and use it in GitHub Desktop.
require "mkmf" | |
create_makefile("string_alloc_test") | |
raise "Unable to compile" unless system("make") | |
require_relative "string_alloc_test.so" | |
require "benchmark/ips" | |
include StringAllocTest | |
def r_alloc | |
"abcdef" | |
end | |
@str = nil | |
def r_reuse | |
@str ||= "abcdef" | |
end | |
def r_freeze | |
-"abcdef" | |
end | |
Benchmark.ips do |x| | |
x.time = 0.2 | |
x.warmup = 0.1 | |
puts "ruby #{RUBY_VERSION}" | |
[:c_alloc, :c_reuse, :r_alloc, :r_reuse, :r_freeze].each do |m| | |
p [send(m), send(m).object_id, send(m), send(m).object_id] | |
x.report(m, m.to_s) | |
end | |
x.report("new string literal", '"abcdef"') | |
x.report("reuse string literal", '-"abcdef"') | |
end |
low power AMD-C50 CPU, Ruby-2.7.0:
$ ruby string_alloc_test.rb
ruby 2.7.0
Calculating -------------------------------------
c_alloc 2.156M (± 1.3%) i/s - 439.152k in 0.203710s
c_reuse 3.093M (± 0.6%) i/s - 649.242k in 0.209913s
r_alloc 2.206M (± 1.8%) i/s - 491.265k in 0.222723s
r_reuse 2.542M (± 0.7%) i/s - 526.340k in 0.207047s
r_freeze 4.038M (± 7.1%) i/s - 823.836k in 0.205290s
new string literal 13.088M (± 4.3%) i/s - 2.657M in 0.203476s
reuse string literal 10.688M (± 8.1%) i/s - 2.167M in 0.204137s
low power AMD-C50 CPU, Ruby-2.3.7:
$ ruby string_alloc_test.rb
ruby 2.3.7
["abcdef", 47454878193680, "abcdef", 47454878193500]
["abcdef", 47454878189920, "abcdef", 47454878189920]
["abcdef", 47454878170240, "abcdef", 47454878170020]
["abcdef", 47454878166860, "abcdef", 47454878166860]
["abcdef", 47454878165380, "abcdef", 47454878164260]
Calculating -------------------------------------
c_alloc 2.053M (± 3.7%) i/s - 434.646k in 0.211978s
c_reuse 3.342M (± 1.7%) i/s - 705.026k in 0.211020s
r_alloc 2.770M (± 3.8%) i/s - 554.708k in 0.200517s
r_reuse 2.564M (± 0.9%) i/s - 559.229k in 0.218156s
r_freeze 1.374M (± 2.5%) i/s - 309.184k in 0.225096s
new string literal 10.962M (± 1.5%) i/s - 2.209M in 0.201594s
reuse string literal 1.648M (± 3.3%) i/s - 348.656k in 0.211751s
Intel 4 core i5-2400:
$ ruby --jit string_alloc_test.rb
ruby 2.7.0
Calculating -------------------------------------
c_alloc 16.085M (± 2.5%) i/s - 3.281M in 0.204119s
c_reuse 27.802M (± 1.2%) i/s - 5.646M in 0.203111s
r_alloc 26.708M (± 2.9%) i/s - 5.403M in 0.202481s
r_reuse 30.087M (± 1.3%) i/s - 6.272M in 0.208512s
r_freeze 165.940M (± 1.7%) i/s - 33.333M in 0.200935s
new string literal 302.848M (± 1.9%) i/s - 61.001M in 0.201500s
reuse string literal 275.269M (± 2.1%) i/s - 55.193M in 0.200598s
Two questions:
- How is calling
:r_alloc
different from'"abcdef"'
? (calling overhead?) - Is
x.report(m, m.to_s)
equivalent tox.report(m) { send(m) }
?
I think you should also compare with frozen_string_literal
pragma and calling String.new("abcdef")
and calling +"abcdef"
- How is calling
:r_alloc
different from'"abcdef"'
? (calling overhead?)
Exactly, it's with and without the method call.
- Is
x.report(m, m.to_s)
equivalent tox.report(m) { send(m) }
?
Similar it's with and without the block invocation, see here.
I think you should also compare with
frozen_string_literal
pragma and callingString.new("abcdef")
and calling+"abcdef"
Feel free to fork and add more variations. For me the comparison between c_alloc
and c_reuse
was the most interesting part. I extended the C part a bit more to add somewhat more variation to the st_table
. It slowed down r_reuse
somewhat, but it was still faster than creation of new strings.
Thank you for the clarifications :)
The corresponding C code is here.
Intel 4 core i5-2400: