From [[Gogaruco 2012]]
Presenter: [[Charles Nutter]]
Charles works on JVM languages at Red Hat, focusing on Ruby but expanding to other languages soon. He has worked on JRuby for the past eight years and has been a JVM enthusiast since Java 1.0. Charles hopes to make JRuby the best Ruby implementation for high performance, big data, and heavy loads, and to use lessons learned from JRuby to help the JVM and other languages that run on it meet their potential.
For years, the JVM has been the runtime to beat when it comes to runtime optimization and garbage collector performance. While statically-typed languages built atop the JVM have been able to leverage those capabilities, dynamic languages have often had a more difficult time. But the times they are a'changing.
Java 7 brings to the JVM a new and powerful feature called invokedynamic. With invokedynamic, dynamic languages no longer have an automatic performance penalty. The optimizations that make Java and other statically-typed JVM languages run fast now apply to dynamic languages just as well. Imagine a world where Ruby runs as fast as Java, with nearly zero GC overhead, true parallel threads, massive heap sizes, and rock-solid stability. That's the potential of invokedynamic, the JVM, and JRuby, and I'm going to show you how it all fits together.
- High Perf = faster than you need it to be.
- You hit a performance wall at some point.
- What we want:
- Faster execution
- Better GC
- Parallel execution
- Big data
- ...but we can't have these with the current way that C extensions are written.
- Different Appraoch:
- Build our own runtime? YARV, Rubinius, MacRuby
- Use an existing runtime? JRuby, MagLev, MacRuby, IronRuby
- It's "easy" to make a ew VM--but making it competitive is really, really, really hard.
- JVM
- 15+ years of engineering by whole teams
- FOSS
- Fastest VM available
- Best GCs available
- Full parallel threading with guarantees
- Broad platform support
- "But Java is slow"
- Not anymore--it's literally as fast as C in many cases
- In many cases it's the way the code is written
- JRuby
- Java (and Ruby) implementation of Ruby on JVM
- Same memory, threading model
- JRuby JITs to JVM bytecode
- It's been many, many years of hard work
- invokedynamic
- Not just about invoking methods
- Not just about dynamic typing
- JVM 101
- 200 opcodes
- InvokeDynamic lets JRuby teach the JVM how ruby works
- Benchmarking is Hard
- Small code benchmarks very differently from large code
- Rails perf is a mixed bag right now.
- Significant gains for some folks
- Long warmup times for so much code
- The Future
- JRuby will continue to get faster
- Invoke Dynamic improvements at VM-level
- Compiler improvements at Ruby level
JRuby How do we make Ruby fast?
Man hours vs. CPU
Straightline, time
which ruby implementation
ruby faster than other runtimes?
1.9.3 fast enough and 1.8.7 is slow
Can't get done what you want to get done
You're bound by your architecture
Move to different runtime
If you're not writing performance sensitive code in Ruby, you're giving up too easily!!!
Not universally bad, but bad in MRI
What is bad is the way their implemented within CRuby
Unless you're in MRI, you're limited when writing native extensions
Faster execution
Better GC, non-blocking
Parallel Execution via threads or actors within a process
Big data by continuous scans
Can't have any of these with current C extension implementations!
Don't fallback to C, so lets improve Ruby to make it faster.
- Build your own runtime like YARV, Rubinius or MacRuby
- Use an existing runtime like JRuby
Making a new VM is easy (early rubinuius was simple)
Making a new VM competitive is really really hard
15 years of open source experience and super quick
Best GCs available
Full parallel threading
Broad platform support so wide adoption
Rumor is dying because Java is now C fast
Java is terrible for application development because too many abstractions
Simple algorithms can compile to same bytecode as C
The way you write code is much more important than what you write it in
Java implementation of Ruby on JVM
1 to 1 compatible with MRI
JRuby JITs to JVM bytecode
Still things about Ruby which defy optimization such as interpreter optimization
(see slides for great timeline of commits)
Ruby local variables are JVM local variables
Avoid inter-call goo
Eliminate unnecessary work
Everything is a map such as modules, instance variables
Method lookups go up-hierarchy
Lookup target caches result (child caches method defined in parent)
Modification cascades down
Make calls fast
Make constants free
Opcodes / Data endpoints
- Invocation
- Field access getting data out of object
- Array access
All Java code revolves around these endpoints
If you every stray outside of opcodes, you are stuck!
We need millions of operations!
With invokedynamic, we can get around this problem
- invokedynamic bytecode
- bootstrap method
- method handles
- find target method on JVM (see diagram on slides)
Now the path is cached and optimized!
InvokeDynamic lets JRuby teach the JVM how Ruby works, so the JVM can optimize like any other language on the JVM
Benchmarking is really hard
JITs code bodies after 10k calls
Inlines up to two targets
Optimistic by making very aggressive decisions
- Makes optimistic decisions for a small system, but those decisions
- Will have to be reversed for large systems Inlining optimizes and writes bytecode for a chunk of code instead of pieces
Benchmarking is not always enough, you have to read the assembly generated by JVM
Benchmarks are synthetic
Every system is different
Figure out what is slow in your system, and benchmark this part of your system
Significant gains for some folks
Expand where JRuby optimizes such as super
Optimize things like respond_to?
or method_missing
Ruby flip-flops http://stackoverflow.com/questions/1111286/when-would-a-ruby-flip-flop-be-useful
JRuby will get faster!
InvokeDynamic will get faster!