Search code examples
rubyperformance

Performance in different variable scopes?


I wrote a simple test case:

$g = 10
def fun_g a
  a += $g
end

def fun_l a
  l = 10
  a += l
end

def fun_gl a
  $gl = 10
  a += $gl
end

def test fun
  t = Time.now

  (10 ** 6).times { |n|
    method(fun).call(n)
  }

  puts(Time.now - t)
end

test :fun_g
test :fun_l
test :fun_gl

The result is something like below. It seems that the first function fun_g is the fastest, and the fun_gl is the slowest.

1.249626
1.268355
1.30267

But I also get result that indicates the fun_l is the fastest.

1.27436
1.25794
1.303973

Theoretically, which one should be the fastest? What if I change the example to a compiled language, will the result still be the same? Will the compiler optimize the local variables to global ones?


Solution

  • I have converted this to use the STDLIB benchmark and got this result

    require 'benchmark'
    
    iterations = 10 ** 7
    $global = 0
    local = 0
    @instance = 0
    Benchmark.bmbm(8) do |x|
      x.report('global') {iterations.times { $global } }
      x.report('local') {iterations.times { local } }
      x.report('instance') {iterations.times { @instance  } }
    end
    

    The results:

    Rehearsal --------------------------------------------
    global     1.580000   0.010000   1.590000 (  1.600952)
    local      1.540000   0.000000   1.540000 (  1.555683)
    instance   1.600000   0.000000   1.600000 (  1.642781)
    ----------------------------------- total: 4.730000sec
    
                   user     system      total        real
    global     1.560000   0.000000   1.560000 (  1.575711)
    local      1.540000   0.000000   1.540000 (  1.547040)
    instance   1.600000   0.010000   1.610000 (  1.618772)
    

    Using benchmark-ips gem:

    require 'benchmark/ips'
    
    $global = 0
    local = 0
    @instance = 0
    
    Benchmark.ips do |x|
      x.report('global') { $global }
      x.report('local') { local }
      x.report('instance') { @instance }
      x.compare!
    end
    

    Gives the following report on my machine at this time, and perhaps gives a more easily read comparison:

    Calculating -------------------------------------
                  global    34.310k i/100ms
                   local    34.461k i/100ms
                instance    34.383k i/100ms
    -------------------------------------------------
                  global      3.154M (± 2.9%) i/s -     15.748M
                   local      3.205M (± 4.5%) i/s -     15.990M
                instance      3.153M (± 3.1%) i/s -     15.747M
    
    Comparison:
                   local:  3205049.9 i/s
                  global:  3153595.5 i/s - 1.02x slower
                instance:  3152813.3 i/s - 1.02x slower
    

    You had compared only local variable and global variables but neglected instance variables.

    There is very negligible difference in any, which is actually a good thing.

    I am not sure this answers your question, but hope it helps.