Attached is a broken, experimental patch that makes the compiler aware of scoping method calls. In cases where no scope is needed, it will not create a dynamic scope and will instead use Java local variables for Ruby local variables. The performance increase is extremely impressive.

## before

~/NetBeansProjects/jruby $ jruby -J-server -C test/bench/bench_fib_recursive.rb
  1.323000   0.000000   1.323000 (  1.323000)
  1.118000   0.000000   1.118000 (  1.119000)
  1.055000   0.000000   1.055000 (  1.056000)
  1.054000   0.000000   1.054000 (  1.054000)
  1.055000   0.000000   1.055000 (  1.054000)
  1.055000   0.000000   1.055000 (  1.055000)
  1.055000   0.000000   1.055000 (  1.055000)
  1.049000   0.000000   1.049000 (  1.049000)

~/NetBeansProjects/jruby $ jruby -J-server -J-Djruby.jit.threshold=0 test/bench/bench_method_dispatch_only.rb
Test interpreted: 100k loops calling self's foo 100 times
  3.901000   0.000000   3.901000 (  3.901000)
  4.468000   0.000000   4.468000 (  4.468000)
  2.446000   0.000000   2.446000 (  2.446000)
  2.400000   0.000000   2.400000 (  2.400000)
  2.423000   0.000000   2.423000 (  2.423000)
  2.397000   0.000000   2.397000 (  2.397000)
  2.399000   0.000000   2.399000 (  2.399000)
  2.401000   0.000000   2.401000 (  2.401000)
  2.427000   0.000000   2.427000 (  2.428000)
  2.403000   0.000000   2.403000 (  2.403000)

## after

~/NetBeansProjects/jruby $ jruby -J-server -C test/bench/bench_fib_recursive.rb
  2.360000   0.000000   2.360000 (  2.360000)
  0.818000   0.000000   0.818000 (  0.818000)
  0.775000   0.000000   0.775000 (  0.775000)
  0.773000   0.000000   0.773000 (  0.773000)
  0.799000   0.000000   0.799000 (  0.799000)
  0.771000   0.000000   0.771000 (  0.771000)
  0.776000   0.000000   0.776000 (  0.776000)
  0.770000   0.000000   0.770000 (  0.769000)

~/NetBeansProjects/jruby $ jruby -J-server -J-Djruby.jit.threshold=0 test/bench/bench_method_dispatch_only.rb
Test interpreted: 100k loops calling self's foo 100 times
  3.100000   0.000000   3.100000 (  3.100000)
  3.487000   0.000000   3.487000 (  3.487000)
  1.705000   0.000000   1.705000 (  1.706000)
  1.684000   0.000000   1.684000 (  1.684000)
  1.678000   0.000000   1.678000 (  1.678000)
  1.683000   0.000000   1.683000 (  1.683000)
  1.679000   0.000000   1.679000 (  1.679000)
  1.679000   0.000000   1.679000 (  1.679000)
  1.681000   0.000000   1.681000 (  1.681000)
  1.679000   0.000000   1.679000 (  1.679000)

In each case this represents an improvement of about 25-30%, just be eliminating the construction of DynamicScope each call and using local variables instead of an array.

Now as I mentioned this is entirely experimental, but it does demonstrate what's possible as we eliminate more and more JRuby per-call overhead and depend more upon what the JVM gives us out of the box.

Making this sort of change work long-term is going to be a tricky matter. A few things stand in our way:

- blocks require a way to save off local variables and modify them outside the normal line of execution. For example, a = 1; x = Proc.new { puts a }; a = 2; x.call should puts "2", since the Proc is actually scoped within this method. There's no way to pass a reference to the local Java scope, so we have to fall back on passing some value holder at that point. - eval also requires access to the local scope, in much the same way that a normal block (non-proc) does. eval executes in the same thread, and the current method can't exit or proceed until the eval is complete, so there's not the same unusual execution patterns you get with Procs. However...eval and its kin are methods instead of keywords, and we can't technically detect when eval lives in a method body. - accessing the current lexically enclosing class requires scoping now, since there's no longer a cref stack. This could be fixed by storing it in a different way in compiled code that's compatible with interpretation. - a few other methods require access to a scope object, like local_variables. Again, if these were keywords we could detect them, but they're methods and complicate matters.

However, I still believe it's possible. In some cases, we can just treat those special methods as keywords until they are no longer keywords. In other cases, we just need a way to execute without scoping and framing constructs and create them lazily when needed. It's not going to be particularly easy...but I do believe it's possible.

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email

Reply via email to