JRuby

High Performance Ruby

High Performance Ruby

by Charles Nutter

In the video 'High Performance Ruby' presented by Charles Nutter at GoGaRuCo 2012, the focus is on optimizing Ruby's performance through the JRuby implementation. Nutter, a prominent member of the JRuby development team at Red Hat, emphasizes the importance of enhancing Ruby's speed and efficiency, particularly in production environments.

Key Points Discussed:
- Introduction to JRuby: Nutter opens by asking attendees about their experience with JRuby, revealing a growing interest in its capabilities.
- Performance Metrics: He differentiates between two definitions of performance—user satisfaction in writing maintainable code quickly and the raw performance of executing code on larger applications. Nutter argues that while Ruby may not initially match unmanaged languages' performance, it can still be deemed high-performance if adequate for application requirements.
- Historical Context: The discussion contrasts Ruby 1.8.7 with 1.9.3, stressing that as applications grow, the need for improved performance becomes critical. Nutter cautions against solely relying on native C extensions for performance improvements due to their invasive nature and limited support.
- Garbage Collection (GC) Challenges: A major theme is the need for better garbage collection strategies, which currently hinder Ruby performance under load, especially in large applications.
- Benefits of JRuby: Nutter advocates for JRuby as a viable solution, highlighting its use of the JVM with advanced garbage collection and threading capabilities, along with leveraging existing performance-optimized runtimes like OpenJDK HotSpot.
- Performance Optimization Techniques: The use of invoke dynamic for method invocation efficiency, caching techniques, and simplifying method lookups are presented as strategies to enhance Ruby execution.
- Real-World Benchmarking: Nutter calls for a shift in focus towards benchmarking real-world applications, particularly frameworks like Rails, to better illustrate JRuby's capabilities.

Conclusions and Takeaways:
- JRuby represents a significant step forward in Ruby performance optimization, capable of supporting complex applications effectively. Nutter emphasizes an ongoing commitment to refining JRuby and inviting community feedback to enhance its development further. The session closes with an encouragement to explore JRuby's potential for improving Ruby-based applications, aligning Ruby's benefits with those of modern performance-optimized environments.

00:00:08.679 I'm really glad to have someone here to talk about JRuby. JRuby is a big deal, and you should all be paying attention to it. I'm really happy to have Charlie Nutter here; he's at Red Hat and is one of the principal minds behind JRuby. He works on JVM languages at Red Hat, doing a lot of cool stuff.
00:00:16.880 He's going to tell you about making Ruby high performance. Thank you, Charlie.
00:00:39.000 All right, I have to ask the usual introduction questions. How many people here have ever used JRuby for something? Wow! How many people are using it for something in production right now? Okay, fewer, but we're getting there; a lot more people have tried it out, which is promising.
00:00:52.879 I'm going to talk specifically about JRuby and how we're trying to optimize Ruby. More generally, I will discuss the challenges we face and some of the ways we are looking to make Ruby faster and actually turn Ruby into a higher performance language.
00:01:11.439 So, basic contact info: I am one of the JVM language guys at Red Hat, specifically in the JBoss Polyglot group, which is working on polyglot web server applications and services within JBoss. I'm mostly focused on JRuby right now, but hopefully after JRuby 1.7 is done in the next month or so, I will start looking at applying what we've learned to some of the other JVM languages as well.
00:01:41.439 What does performance mean when it comes to Ruby? There are usually two metrics people refer to regarding Ruby performance. First is the classic idea that man-hours are more expensive than CPU hours. Ruby may not be the fastest language, but we can write applications quickly and maintain them easily. Users are generally happy when they use Ruby. By this measure, Ruby can already be considered a high-performance language if the goal is to write and maintain applications efficiently.
00:02:31.160 However, I will be discussing the other definition of performance, which typically relates to the bottom line of older applications as they grow larger. We need to improve the raw performance of running code and make it better within Ruby.
00:03:09.599 So what is high performance? High performance means being faster than other Ruby implementations. It's something I personally care about, ensuring we can achieve better performance compared to managed languages like C. People often claim Ruby isn't as fast as Java, .NET, or other systems, which raises the question of whether it can be considered high performance when it lags behind.
00:03:49.519 Unmanaged languages like C have raw performance benchmarks we want Ruby to match or even exceed someday. But the real question is, is that a reasonable goal? And do we even need to reach that goal? High performance should really mean that it's fast enough for the tasks you need to accomplish.
00:04:19.639 For example, if you're running a website or a Rails application, achieving high performance may not be a daunting challenge, especially if you have other backend services doing heavy lifting. However, we want the flexibility to use Ruby throughout our systems without needing to rely on alternatives constantly.
00:05:03.919 Many have claimed that Ruby 1.8.7 was fast enough, but now that 1.9.3 has been released, it’s considerably better. The new phrase is that now 1.9.3 is fast enough, but what about those who found 1.8.7 satisfactory? Were they lying, or did they simply not need the performance gains offered by 1.9.3?
00:05:44.520 For any growing application, there will come a time when ‘fast enough’ won't be sufficient. You might hit a performance wall when you can't manage to get the necessary work done given your CPU and monetary resources. In that case, options include moving to a different runtime or even back to an earlier version like 1.8.7, or seeking a performance hit with C extensions, which can often lead developers astray.
00:06:25.520 One of my claims is that if you aren’t writing performance-sensitive code in Ruby, you might be giving up too easily. There are other methods for improving performance, and JRuby is one of them. We'll explore how we are working to enhance Ruby's performance.
00:07:03.360 Many developers fall back on native extensions to gain performance boosts. While integrating existing libraries whose functionality isn’t available in Ruby is not a universally bad idea, the current C API for extensions is quite invasive.
00:07:31.200 It allows for direct access to pointers and requires developers to interact with the internals of objects frequently. As a result, unless you're using Ruby MRI, support for this API can be quite limited, and even MRI itself can struggle operationally to provide resources. Out of Ruby's performance goals, it’s crucial to run code faster, and this may involve incorporating a JIT compiler or enhancing garbage collection.
00:08:51.680 Even with Ruby 1.9.3, extensive GC pauses have been reported in production applications. The overall CPU consumption from GC often falls within the 10 to 20% range, which is wasted cycles. To combat this, we require a more efficient GC system. Furthermore, we strive to enable parallel execution to effectively utilize all cores without launching numerous processes.
00:10:24.240 As Ruby applications grow in size, the performance hit from GC can exacerbate as the application continues to accumulate objects in memory. This results in longer scan times for Ruby’s GC, consuming time and processor resources.
00:11:13.360 Unfortunately, the methods available for C extensions impede progress. C extensions require pointer access, which means it is impossible to shift memory locations. For example, relocating older data into a GC-free zone to avoid being collected by GC would not work.
00:12:10.160 Building a JIT that seamlessly works with C extensions is significantly more complex under current practices. Furthermore, parallel execution lacks guarantees due to uncertain native code writing, as no standardized memory models or guidelines exist for implementing parallelism with C extensions.
00:12:53.760 This is where a different approach may come in: instead of turning to C and its extensions, we ought to ask if we can enhance Ruby itself to be considerably faster. We have two options for improvement: either building our own runtime or using an existing performance-optimized runtime.
00:13:48.640 JRuby represents the latter choice—leveraging the JVM. By incorporating JVM's design, we benefit from 15 years of engineering effort, especially concerning technologies like OpenJDK HotSpot. This open-source runtime is recognized for its extreme performance benefits. It undoubtedly surpasses managed runtimes, outperforming .NET in comparative benchmarks.
00:15:29.960 Moreover, the JVM has the finest garbage collectors currently available, attributed to innovative research over the past decade. The HotSpot VM features six distinct GC options that utilize parallel processing and significantly reduce pause times, allowing for guaranteed short pauses.
00:16:58.800 The major JVMs have successfully resolved the intricacies of implementing parallel threading, which JRuby can take advantage of while developing. Additionally, the broad platform support offered by the JVM includes many server operating systems, ensuring that JRuby functions anywhere.
00:18:15.440 It is worth addressing a lingering misconception that Java is slow; although it faced this criticism historically, Java has emerged as a rapid, high-performance language. Developers often misinterpret Java's speed due to the extensive level of abstraction required when building applications, which detracts from performance.
00:19:43.520 Consequently, while mathematically equivalent algorithms may compile down to similar assembly code between Java and C/C++, the way you write code will drastically impact your performance, regardless of language.
00:20:24.960 Finally, JRuby combines the best of both worlds by bringing Ruby to the JVM while also integrating JVM capabilities directly into Ruby. JRuby 1.6 was released with solid Ruby 1.9.2 support while JRuby 1.7 is on the cusp of better 1.9.3 support.
00:21:18.560 Jruby maintains the same memory and threading models as the JVM. Everything is inherited, ensuring that we can eventually JIT compile Ruby code into JVM bytecode that can then be transformed into native code.
00:23:04.160 Optimizing Ruby's execution has proven to be a long road as nobody has discovered all the ‘magical’ solutions to making Ruby fast across the board. Over the prior six years, JRuby has made remarkable strides, but numerous challenges remain, with particular methods still defying optimization.
00:24:50.440 Efforts continue in enhancing JRuby performance, ensuring string, array, and hash methods run rapidly without significant performance issues. The commitment is to repeat this optimization process until we find effective strategies.
00:25:44.760 In examining the evolution of JRuby, it can be traced back to 2001 with the first contributions arriving over time. Following an initial burst of activity, development stagnated before reviving under Tom Enebo and eventually expanding when I joined forces in 2005 to revitalize the interpreter. It was in 2006 that we grasped a significant momentum due to firm connections at Sun Microsystems.
00:26:57.520 As of today, the activity level remains robust, dedicated to continuing the upgrade of JRuby, aligning the system's execution with what the JVM expects to improve performance for Ruby arguments and eliminating excessive overhead in the process.
00:28:46.960 The core tenet of performance optimization is eliminating unnecessary work. Different components within Ruby, such as modules and classes, comprise maps that could lead to wasted cycles. Simplifying method lookups aids in reducing overhead, and we can cache methods for improved access.
00:29:43.760 Handling constant lookups is slightly more intricate due to variations in lexical scopes, requiring a reliable system without excessive overhead. By architecting instance variable access effectively, Ruby can sidestep the traditional hashing overhead, ultimately saving on unnecessary compute resources.
00:30:37.680 Implementing invoke dynamic serves as a vital tool to aid JRuby. Invoke dynamic provides more freedom over method invocation and other dynamic behaviors, leading to performance improvements. This includes areas such as dynamic typing and instance variables, which aren't statically defined but require runtime decision-making.
00:31:29.640 Within the JVM, there are 200 operations available. Among them, 10 to 16 act as data endpoints for various methods. Emphasizing performance, JRuby effectively employs invoke dynamic to enhance the efficiency of its execution, and this agility holds benefits for JRuby compared to other Ruby implementations.
00:32:35.520 By capitalizing on the capabilities of invoke dynamic, JRuby can sidestep limitations imposed by standard JVM operations, thereby optimizing the Ruby execution pathways.
00:33:39.680 The success of JRuby's optimization efforts will be marked by effective benchmarking. While benchmarking poses its own challenges, especially in a dynamic optimization context like the JVM, the ability to monitor how the JVM dynamically changes its optimizations helps demonstrate the program's performance.
00:34:59.840 Instead of relying solely on synthetic benchmarks, we need real-world applications that accurately represent expected workloads. Therefore, our future testing must shift focus toward substantial applications to truly measure JRuby's performance under load.
00:36:13.920 As we explore the robustness of JRuby, we seek metrics relevant to significant frameworks such as Rails, which relies on core Ruby classes requiring optimization for maximum efficiency. Recognizing these complexities ensures that we develop solutions designed for these challenging areas.
00:37:48.080 In conclusion, our objective is to enhance JRuby performance continually. With its development being an iterative process, we are committed to identifying areas for improvement while remaining open to community feedback regarding which enhancements would best support the many Ruby frameworks.
00:39:19.480 JRuby will progress, with strides toward optimization and enhancements from the ongoing efforts. Given its open-source capabilities, it is an ideal time to explore JRuby options and gauge its potential for transforming your Ruby applications. Thank you.
00:40:05.920 Okay, apparently I've timed this exactly at 45 minutes.
00:40:10.760 Long.