Celluloid
Performance Optimization in Ruby
Summarized using AI

Performance Optimization in Ruby

by Prathmesh Ranaut

In this presentation titled "Performance Optimization in Ruby," Prathmesh Ranaut shares insights from his experience optimizing the concurrency framework Celluloid, achieving performance improvements of up to 300%. Focusing on effective strategies to enhance Ruby application performance, he outlines actionable techniques developers can implement.

Key Points Discussed:

  • Understanding Performance Optimization: Performance optimization entails achieving more with fewer resources, rather than simply scaling up by adding more servers. It is crucial to address performance bottlenecks for sustainable improvement.
  • Tip 1: Benchmarking Suite: A vital first step is establishing a benchmarking suite to measure performance accurately. Without this, one cannot definitively ascertain if changes have resulted in improved app performance.
  • Tip 2: Upgrade Ruby Version: Upgrading from older versions (e.g., Ruby 1.8 to 2.0 or higher) can lead to significant performance gains through improved memory management and garbage collection features introduced in recent Ruby releases.
  • Tip 3: Explore Ruby Implementations: Different implementations like JRuby can offer better performance for specific workloads, though users should be aware of any trade-offs, such as JVM overhead.
  • Tip 4: Method Profiling: Utilizing profiling tools is imperative for identifying performance hotspots in the code, allowing developers to focus optimization efforts effectively.
  • Tip 5: Identify Bottlenecks: Understanding where most processing time is expended—be it CPU or I/O—allows developers to optimize the correct parts of the application.
  • Tip 6: Multi-threading: Implementing multi-threading, especially using frameworks like Celluloid, can lead to substantial performance improvements in Ruby applications.

Tools Introduced:
- Method Profiler for collecting execution time data.
- Kcachegrind for visualizing CPU time consumption.
- Ruby Prof for thread performance analysis.
- ObjectSpace for monitoring object creation and memory optimization.
- Drace for real-time CPU monitoring, recommended for further exploration.

In conclusion, Ranaut emphasizes that performance optimization is an ongoing process that requires a methodical approach. By leveraging the right tools and strategies, Ruby developers can significantly enhance the performance of their applications. The session encourages participants to think critically about their performance strategies and to actively seek improvements.

00:00:12.599 Hi Australia! How are you doing? So far, there have been a lot of amazing presentations today, and I hope this one is one of them too. It's my first talk ever at a conference, and I'm pretty excited as well as somewhat nervous. Thank you for the support!
00:00:32.079 I'm going to be talking about performance optimization in Ruby and how to do simple things that make your app run faster. Before we go any further, I should mention that I’m new to Australia, and Melbourne. Speaking of Melbourne, the weather has been quite unpredictable—chilly in the morning, yet now it's hot again! The weather here changes faster than the code I write—just kidding! My code runs fast too!
00:01:20.431 I added this slide because I learned that you can add emojis to presentations yesterday, and I just wanted to give it a go. A bit about myself—I’m a computer science undergrad and have assisted hundreds of Ruby applications in fixing performance bottlenecks. You might be familiar with Celluloid, which is one of my notable works—it's a concurrency framework for Ruby. Last summer, I worked on it and managed to make it around 300% faster, which I think is pretty substantial!
00:02:04.240 Most of the tips I’m going to share are based on my experience optimizing Celluloid. So, what exactly is performance optimization? You might be a new venture-funded unicorn that views performance optimization as simply spinning up more dynos in Heroku, but is it really that simple? To me, performance optimization means doing more with fewer resources, which can be somewhat counterintuitive to scaling.
00:02:50.799 Don't get me wrong; there are times when you do need more servers. However, throwing more servers at bloated, slow code won't resolve the underlying problems—you eventually need to improve performance. So, how exactly do you optimize? Here are six tips you can try to make your app run faster.
00:03:16.480 Tip number one: always have a benchmarking suite. When developing a program, one of the last steps should be to ensure it is as fast as possible. I've seen many apps without benchmarking suites where a developer makes a change and, for some reason, it runs faster for a moment. They then jump from their chair and run to their project manager, exclaiming they've made the site faster! Without a benchmarking suite, you really can’t claim any performance improvements.
00:03:53.760 So, a benchmarking suite is absolutely necessary. Benchmarking IPS is one amazing tool I use often; it tells you how many times a function can be called per second. For example, with the Benchmark IPS Gem, this code calculates how many times two numbers can be added in a second. It shows you how many times a function can run per second. If you run it, you will get results indicating that I can add one and two approximately 12.5 million times per second, which is pretty fast! However, there is always room for improvement.
00:04:58.840 Tip number two: upgrade your Ruby version. I met someone yesterday who was still using Ruby 1.8—they were too busy writing new features to upgrade deprecated methods! For anyone still running on 1.8, please upgrade to 1.9! You will be amazed by the performance improvements it offers. Ruby 2.0 has a feature called copy-on-write, which optimizes memory usage by allowing sharing of memory between parent and child processes until one of them modifies the data.
00:05:32.520 Moreover, Ruby's garbage collection has been a challenge for some time, but with Ruby 2.1, we introduced Generation Garbage Collection, which partitions heap space into young and old scopes to improve efficiency. Each iteration reduces the heap data to scan through, making Ruby perform faster overall.
00:06:11.279 Moving forward, tip number three: try another implementation of Ruby. You can benchmark your application on different versions; for example, JRuby offers faster performance for calculations than MRI. However, it comes with some shortcomings due to JVM overhead. Use a benchmarking suite to find out which Ruby implementation works best for your application.
00:06:45.760 Here's a benchmark comparing Ruby 2.3 and JRuby. While I mentioned 12.4 million times faster on its own, JRuby can perform calculations at nearly twice that speed in roughly the same time. Another interesting Ruby implementation currently in development is JRuby with Truffle, which claims to be 31% faster than Ruby 2.3.
00:07:58.160 Moving to tip four: always profile your methods. Profiling helps pinpoint the lowest-hanging fruits to improve app performance. I’ll show you some tools later on, so hang tight! Tip five: when generating your benchmarking suite, identify potential bottlenecks. Understanding why your code runs slowly will save you time—optimize the functions that are rarely used, not the ones that are called frequently.
00:09:01.400 You need to determine where the majority of processing time is spent. Is it I/O operations or excessive CPU calculations? Here comes tip six: consider multi-threading. This can greatly improve performance, especially relevant in discussions around actors and Celluloid. If you're not a fan of Elixir, I'd recommend trying Celluloid as it significantly enhances application performance.
00:10:19.680 As for implementations of Ruby with Celluloid, try JRuby or Rubinius, as both are well supported. Now, let’s shift to some tools I frequently use. The first tool is the Method Profiler, which collects performance information about methods in your objects and creates detailed reports regarding execution times. This is directly tied to the previous tip.
00:12:06.720 Next, we have Kcachegrind, a call graph viewer that provides advanced insights by telling you how much CPU time each method consumes, using a GUI to visualize this information. If you are on MRI, you won’t see values over 100%, but multi-threading can higher those numbers.
00:13:14.759 Another useful tool is Ruby Prof. It allows you to easily visualize which parts of your code are running slowly by breaking down your program's performance per thread. For example, you might find that a certain method is utilizing 99.9% of CPU time.
00:13:49.919 Moving on, ObjectSpace counts objects, helping with memory optimization by checking the number of objects created before and after specific code execution. By disabling garbage collection before running your code, you can examine the spike in object creation, allowing you to fine-tune your memory usage.
00:15:06.519 Lastly, there's Drace, which I've heard is great for real-time CPU monitoring. While I have not personally used it, it's been recommended as a definitive tool for such monitoring tasks, so you may want to consider trying it!
00:15:46.880 Thank you all very much for being here at RubyConf AU! I hope you're having a great time!
00:17:00.000 Do we have a couple of minutes for questions? Does anyone have any specific questions?
00:17:17.280 Speaker answers questions regarding Rubinius and JRuby, clarifying that the goal is to optimize both frameworks, with a focus on collaboration with the Rubinius core team. Thank you!
Explore all talks recorded at RubyConf AU 2017
+16