On 7/10/06, Nick Sieger <[EMAIL PROTECTED]> wrote:
Aside from the gross overhead of interpretation (which we'll never be able to eliminate without a compiler) it's most likely the high amount of per-method object churn and dispatch logic.
- Multiple transient collections allocated for every method hit
- Lots of collection overhead
- Lookup of method objects (big hit at first, less after cached)
- Reflection versus direct invocation
- Constantly calling threadlocal to get access to thread context, sometimes multiple hits in a given method
Some of these can be improved with a little cleanup, like always getting the ThreadContext into a local var before doing other things (rather than doing repeated getRuntime().getThreadContext() calls). Some will require refactoring, like passing TC to all method invocations rather than calling back to a threadlocal every time. At the moment, I'm focusing on reducing the interpreter cost; I've got some fixes on the way that improve a simple 1_000_000.times { x = x + 1} test case by about 16%. Tom's looking at reducing inter-method costs, by eliminating unnecessary collection churn and simplifying per-thread primitives like frames and scopes. We logically should be able to get things as fast or almost as fast as C Ruby before we even tackle compilation, since we know our object allocation, GC, threading, and IO are all going to be faster.
It still amazes me how many people are stuck on the "Java is slow" thing. It's so not. With compilation, however, there are optimizations possible for JRuby; if a fixnum is only used within a given method and we can determine it's never passed out, we could replace it with a bare primitive and perform fixnum ops against that. That could result in gross performance improvements for number-heavy code. (I limit this to intra-method use because across method boundaries we need something more substantial to pass around, and that something needs to implement IRubyObject).
INVOKEDYNAMIC would eliminate method lookup for builtin classes; we'd just have the JVM take the hit of doing that dispatch, which may or may not be faster (probably faster). It wouldn't cost much to start using INVOKEDYNAMIC...just another ICallable type that stores whatever INVOKEDYNAMIC needs and knows how to make it happen.
It's a good bump, but like you say, still slow. Where do you suspect we're losing so much performance? String manipulation and unnecessary object creation?
Aside from the gross overhead of interpretation (which we'll never be able to eliminate without a compiler) it's most likely the high amount of per-method object churn and dispatch logic.
- Multiple transient collections allocated for every method hit
- Lots of collection overhead
- Lookup of method objects (big hit at first, less after cached)
- Reflection versus direct invocation
- Constantly calling threadlocal to get access to thread context, sometimes multiple hits in a given method
Some of these can be improved with a little cleanup, like always getting the ThreadContext into a local var before doing other things (rather than doing repeated getRuntime().getThreadContext() calls). Some will require refactoring, like passing TC to all method invocations rather than calling back to a threadlocal every time. At the moment, I'm focusing on reducing the interpreter cost; I've got some fixes on the way that improve a simple 1_000_000.times { x = x + 1} test case by about 16%. Tom's looking at reducing inter-method costs, by eliminating unnecessary collection churn and simplifying per-thread primitives like frames and scopes. We logically should be able to get things as fast or almost as fast as C Ruby before we even tackle compilation, since we know our object allocation, GC, threading, and IO are all going to be faster.
A fascinating comparison, nonetheless. That pure java number is such a tease when considering that we'll never really get there.
It still amazes me how many people are stuck on the "Java is slow" thing. It's so not. With compilation, however, there are optimizations possible for JRuby; if a fixnum is only used within a given method and we can determine it's never passed out, we could replace it with a bare primitive and perform fixnum ops against that. That could result in gross performance improvements for number-heavy code. (I limit this to intra-method use because across method boundaries we need something more substantial to pass around, and that something needs to implement IRubyObject).
Somewhat offtopic, I wonder how INVOKEDYNAMIC would help in this case -- with the JVM potentially becoming open source soon, I would think it would be a lot easier to get a hold of an early-access patch and compile your own VM. What do you see needing to change in the current interpreter infrastructure to be able to take advantage of it?
INVOKEDYNAMIC would eliminate method lookup for builtin classes; we'd just have the JVM take the hit of doing that dispatch, which may or may not be faster (probably faster). It wouldn't cost much to start using INVOKEDYNAMIC...just another ICallable type that stores whatever INVOKEDYNAMIC needs and knows how to make it happen.
--
Charles Oliver Nutter @ headius.blogspot.com
JRuby Developer @ www.jruby.org
Application Architect @ www.ventera.com
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ Jruby-devel mailing list Jruby-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jruby-devel