Ruby exceptions

At work a discussion arised on how fast a ruby exception is. And if it is usable in Rails projects. The discussion started after the conclusion that performance dramatically degraded in a project using the Rails framework.

The question arose how fast ruby handles exceptions. After doing a quick google I could not find an isolated benchmark so I whipped up one myself.

Below the result of the benchmark.

ruby 1.8.7 (2012-02-08 patchlevel 358) [i686-darwin11.2.0]

  Rehearsal ----------------------------------------------------
  exception          0.770000   0.030000   0.800000 (  0.809420)
  exception with e   0.780000   0.040000   0.820000 (  0.814608)
  multi exception    0.850000   0.040000   0.890000 (  0.885843)
  symbol             0.040000   0.000000   0.040000 (  0.035782)
  ------------------------------------------- total: 2.550000sec

                         user     system      total        real
  exception          0.770000   0.030000   0.800000 (  0.808482)
  exception with e   0.780000   0.040000   0.820000 (  0.817195)
  multi exception    0.850000   0.040000   0.890000 (  0.889478)
  symbol             0.040000   0.000000   0.040000 (  0.036175)

ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.2.0]

  Rehearsal ----------------------------------------------------
  exception          0.890000   0.040000   0.930000 (  0.929162)
  exception with e   0.890000   0.030000   0.920000 (  0.934193)
  multi exception    0.970000   0.040000   1.010000 (  0.999004)
  symbol             0.020000   0.000000   0.020000 (  0.017207)
  ------------------------------------------- total: 2.880000sec

                         user     system      total        real
  exception          0.830000   0.040000   0.870000 (  0.867102)
  exception with e   0.830000   0.030000   0.860000 (  0.873007)
  multi exception    0.910000   0.040000   0.950000 (  0.938906)
  symbol             0.020000   0.000000   0.020000 (  0.017294)

jruby 1.6.7.2 (ruby-1.8.7-p357) (2012-05-01 26e08ba) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [darwin-x86_64-java]

  Rehearsal ----------------------------------------------------
  exception          8.044000   0.000000   8.044000 (  8.006000)
  exception with e   7.704000   0.000000   7.704000 (  7.704000)
  multi exception    7.791000   0.000000   7.791000 (  7.791000)
  symbol             0.038000   0.000000   0.038000 (  0.038000)
  ------------------------------------------ total: 23.577000sec

                         user     system      total        real
  exception          7.603000   0.000000   7.603000 (  7.603000)
  exception with e   7.605000   0.000000   7.605000 (  7.605000)
  multi exception    7.529000   0.000000   7.529000 (  7.529000)
  symbol             0.009000   0.000000   0.009000 (  0.009000)

The benchmark code

  
  require 'benchmark'

  class E1 < StandardError; end
  class E2 < StandardError; end
  class E3 < StandardError; end

  def outer_conditional
    if inner_returns_symbol == :argument_error
      :agument_error
    end
  end

  def outer_multi_exception
    inner_multi_exception
  rescue E1
    :E1
  rescue E2
    :E2
  rescue E3
    :E3
  end

  def inner_multi_exception
    raise [E1, E2, E3][rand(3)]
  end

  def outer_exception
    inner_raises_exception
  rescue ArgumentError
    :argument_error
  end

  def outer_exception_with_e
    inner_raises_exception
  rescue ArgumentError => e
    :argument_error
  end

  def inner_raises_exception
    raise ArgumentError
  end

  def inner_returns_symbol
    :argument_error
  end

  COUNT = 100_000

  Benchmark.bmbm { |x|
    x.report("exception") do
      COUNT.times { outer_exception }
    end
    x.report("exception with e") do
      COUNT.times { outer_exception_with_e }
    end
    x.report("multi exception") do
      COUNT.times { outer_multi_exception }
    end
    x.report("symbol") do
      COUNT.times { outer_conditional } 
    end
  }
  

Fork me on GitHub