Skip to content

Instantly share code, notes, and snippets.

@vojtad
Last active December 10, 2018 19:00
Show Gist options
  • Save vojtad/bc0481fbc9480df8fad9b8d6edb69422 to your computer and use it in GitHub Desktop.
Save vojtad/bc0481fbc9480df8fad9b8d6edb69422 to your computer and use it in GitHub Desktop.
Benchmark: ruby string concatenation

Runtime

@a = 'A', @b = 'B'
Warming up --------------------------------------
s = s + @a; s = s + @b
                        49.000  i/100ms
     s += @a; s+= @b    51.000  i/100ms
s = "#{s}#{@a}"; s = "#{s}#{@b}"
                        50.000  i/100ms
s.concat(@a).concat(@b)
                       452.000  i/100ms
       s << @a << @b   544.000  i/100ms
Calculating -------------------------------------
s = s + @a; s = s + @b
                        657.464  (±30.7%) i/s -      2.793k in   5.000605s
     s += @a; s+= @b    667.024  (±32.1%) i/s -      2.805k in   5.014563s
s = "#{s}#{@a}"; s = "#{s}#{@b}"
                        584.254  (±29.6%) i/s -      2.550k in   5.057047s
s.concat(@a).concat(@b)
                          4.495k (± 3.5%) i/s -     22.600k in   5.035460s
       s << @a << @b      5.390k (± 2.0%) i/s -     27.200k in   5.048399s

Comparison:
       s << @a << @b:     5390.0 i/s
s.concat(@a).concat(@b):     4494.6 i/s - 1.20x  slower
     s += @a; s+= @b:      667.0 i/s - 8.08x  slower
s = s + @a; s = s + @b:      657.5 i/s - 8.20x  slower
s = "#{s}#{@a}"; s = "#{s}#{@b}":      584.3 i/s - 9.23x  slower

Memory

@a = 'A', @b = 'B'
Calculating -------------------------------------
s = s + @a; s = s + @b
                         2.083M memsize (     0.000  retained)
                         2.001k objects (     0.000  retained)
                        50.000  strings (     0.000  retained)
     s += @a; s+= @b     2.083M memsize (     0.000  retained)
                         2.001k objects (     0.000  retained)
                        50.000  strings (     0.000  retained)
s = "#{s}#{@a}"; s = "#{s}#{@b}"
                         2.088M memsize (     0.000  retained)
                         2.001k objects (     0.000  retained)
                        50.000  strings (     0.000  retained)
s.concat(@a).concat(@b)
                         3.112k memsize (     0.000  retained)
                         1.000  objects (     0.000  retained)
                         1.000  strings (     0.000  retained)
       s << @a << @b     3.112k memsize (     0.000  retained)
                         1.000  objects (     0.000  retained)
                         1.000  strings (     0.000  retained)

Comparison:
s.concat(@a).concat(@b):       3112 allocated
       s << @a << @b:       3112 allocated - same
s = s + @a; s = s + @b:    2082741 allocated - 669.26x more
     s += @a; s+= @b:    2082741 allocated - 669.26x more
s = "#{s}#{@a}"; s = "#{s}#{@b}":    2088131 allocated - 670.99x more

Benchmark code

bench method is called from Benchmark.ips and Benchmark.memory blocks. Benchmark.ips is configured using x.config(time: 5, warmup: 1). before method is called once before any benchmarking.

class Benchmarks::StringConcat < Benchmarks::Base
  def bench(x)
    x.report("s = s + @a; s = s + @b") do
      s = ''
      1000.times { s = s + @a; s = s + @b }
      s
    end

    x.report("s += @a; s+= @b") do
      s = ''
      1000.times { s += @a; s+= @b }
      s
    end

    x.report('s = "#{s}#{@a}"; s = "#{s}#{@b}"') do
      s = ''
      1000.times { s = "#{s}#{@a}"; s = "#{s}#{@b}" }
      s
    end

    x.report("s.concat(@a).concat(@b)") do
      s = ''
      1000.times { s.concat(@a).concat(@b) }
      s
    end

    x.report("s << @a << @b") do
      s = ''
      1000.times { s << @a << @b }
      s
    end
  end

  def before
    @a = 'A'
    @b = 'B'

    puts "@a = '#{@a}', @b = '#{@b}'"
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment