Performance Optimization

Slo Mo

Slo Mo

by Richard Schneeman

In the talk titled "Slo Mo" presented by Richard Schneeman at RubyConf 2016, the theme revolves around the paradox of achieving speed in programming by taking a slower, more measured approach to writing code. The talk begins with Schneeman reflecting on societal norms and personal goals, highlighting the importance of reassessing what success truly means. He introduces concepts of personal fulfillment through lower-paced activities, as exemplified by Dr. John Kitchen, who found happiness in skating rather than traditional measurements of success.

The core discussion then shifts to programming performance, specifically focusing on the Sprockets library, which is essential for asset management in Ruby applications. Key points discussed include:

  • Importance of Measuring Performance: Slow code can sometimes yield faster results when measured and analyzed properly.
  • Profiling with StackProf: This tool is used to assess the performance of the Sprockets compilation process; it reveals where time is being consumed the most.
  • Identifying Bottlenecks: The analysis discovers that the method 'set include' is a significant contributor to slow performance due to its extensive recursive calls.
  • Optimization Strategies: Suggestions include avoiding unnecessary hash wrapper layers around data structures and directly using hashes, which can enhance execution speed.
  • Results of Optimizations: Simple optimizations led to performance improvements; for example, a reduction in execution time from 18 seconds to 17.9 seconds, demonstrating that small changes can result in tangible benefits.
  • Collaborative Nature of Optimization: Emphasizing the importance of community discussions among developers to share insights and promote continuous learning in Ruby development.
  • Long-Term Mindset: Encouraging viewers to embrace performance improvement as a journey rather than a singular goal.

Schneeman concludes that while individual programming languages evolve, interaction within the community and a commitment to improving one's craft remain essential. He invites attendees to keep exploring optimizations and learning collaboratively within the Ruby ecosystem, ultimately transforming both their programming practices and personal development in the process.

00:00:19.930 I’d say that before Slo Mo, I became a typical institutionalized educated Western man. In other words, I was driving a BMW to work, working long hours, paying my taxes, and doing everything by the standards of society, just like everybody else in the workforce. Frankly, I intended to work myself into oblivion, grow old, and die—that was pretty much the scenario. But now I see myself as the tip of a great iceberg of consciousness.
00:01:24.600 Hello, everyone! Special thanks to Caleb Thompson for that glorious entrance and to Evan Phoenix, who I heard mumble something about insurance risks. I’d also like to give special thanks to Slow Mo, the movie. I did not take or create the clips; however, I got permission from the creators to use them. You can go and see the whole movie there; it’s a short film that won some awards. Oh man, I forgot my laptop back at the hotel ten minutes before starting this, so I had to run back. I’m legitimately hyped up and ready to go, and I hope you are too. Although we’re supposed to be going slow and breathing—
00:02:14.410 First of all, I’d like to introduce you to Dr. John Kitchen. He is a neurologist who we saw on the screen previously—a very successful doctor with a huge house and all the trappings of a traditionally successful life. He had many fancy cars, but at one point in his life, he was deeply unhappy. Dr. Kitchen evaluated his life and realized that he didn't need that excess. He could live a more focused life by his own rules, not by society's. He chose to reject the traditional notion that more money, more cars, and more houses equate to greater happiness. So he became Dr. John Kitchen the skater.
00:03:24.800 He quit his job, sold his house, sold his cars—although he never actually says that in the movie. He skates around the boardwalk at an incredibly slow pace, which is what he wanted to do. That’s essentially the pinnacle of life for him; that is what makes him happy. So today, I invite you to think about your own goals in life. What do you want to achieve? Do you want to grow up, pick a career, buy a sports car, or retire? If those are your goals, typically, the faster you can achieve them, the better. We often hear of someone retiring early or getting a sports car at 19. Everyone seems to want to be a grown-up as soon as possible, believing life is about reaching your destination as quickly as you can.
00:04:35.280 However, Slow Mo decided that moving very quickly toward the wrong goal was not the right approach. Instead, he turned around, slowed down, and refocused on what truly makes him happy. I'd also like to introduce Schnee Mess, who will be your narrator today. Schnee, pronounced like 'schnapps', is based on part of my last name. He works for a small company based out of San Francisco that you might have heard of called '/oku'. He maintains Sprockets and is part of the Rails contributors team.
00:05:05.970 Today, we’ll be talking a little bit about Sprockets. This talk is about speed. The question arises: why don’t I just cash it in and start a whole new life— reinvent myself? At the last minute, I could kill off my previous identity and start anew. I began to countdown my days and realized all I really wanted to do were the basic things and skate.
00:05:31.450 Every day, I would go out and skate for as long as I could, sometimes even skating through the night. I love to skate—I love the feeling of it. The more attention I could give to it, the more joy I found in the world. It became a spiritual pursuit for me, something religious in some sense. In my mind, I believe that I’m flying in a different way. The fastest way to reach your destination largely depends on where you are headed. In programming, we may get there faster by slowing down, which might seem counterintuitive.
00:06:50.780 Why would we want slower code? Why would we want things to take more time when our goal is to move quickly? One of the primary reasons is that it takes time to measure our programs. If we dedicate time to measuring them, our programs could end up taking longer. As I mentioned, we’re focusing on speeding up Sprockets. Here comes the extremely technical portion of my talk, so brace yourself: Sprockets is slow. Compiling assets is slow. The first thing I did to improve speed was to wrap the Sprockets compilation in a stack profile. Using StackProf, we call our assets precompilation task, allowing us to gather and analyze data on its performance.
00:07:52.080 Using StackProf, we can examine what our program does when it's running. The output from StackProf shows us how Ruby was executing at each moment, and we can see the class name and method name of each call. StackProf records this repeatedly, allowing us to access detailed information without the need for cumbersome timers. However, it does ping Ruby in order to collect this information.
00:08:31.560 Based on the gathered data, we can identify that calling 'set include' and 'sprockets utils digest utils' are the two methods consuming the most execution time. In fact, 'set include' contributes to 26% of the total execution time—a valuable insight, but it doesn’t directly help us.
00:09:22.110 To delve deeper, we can instruct StackProf to focus on just one method, analyzing 'set include'. It turns out that the valid processor calls it 312 times, while ‘DFS paths’ calls it only once. Hence, we should investigate ‘set include’ further. Upon investigation, we find out that it is recursive, calling itself repeatedly. StackProf also provides clarity by displaying this method directly, allowing us to examine its inner workings. We discover that it validates classes and checks if they are strings, arrays, or other types. If it encounters a compound class, like an array, it recursively calls itself.
00:10:40.370 If we notice that ‘set include’ is taking too much time, we may want to consider how it is written. When we check the file for ‘set include’, we find that it’s a Ruby file using a hash variable underneath, which means that while ‘set’ looks like a magic performance enhancer, it is just a wrapper around the hash. This gives us a significant insight on how to enhance performance: we can skip the set and interact directly with a hash instead. Ruby has optimized instructions for hash calls.
00:11:53.180 We can further verify our understanding by generating a string of code, which allows us to behold how Ruby compiles that code. When we compare our initial experimentation with ‘set include’, we observe differences in how Ruby executes the calls. Instead of simply optimizing our code, I sought assistance and queried Siri about optimizing hash calls.
00:13:11.580 It turns out that hash calls are optimized in a specific file, allowing direct calls to hash methods without involving multiple Ruby instruction layers. So while we can see the differences in execution times when calling different methods, we want our approach to be optimized. As a result, we shift our call from ‘set’ to ‘hash’, simplifying the code and enhancing speed.
00:14:30.180 The pertinent question arises whether this adjustment significantly aids in improving performance. During my testing on code triage, I noted that the execution time dropped from about 18 seconds down to 17.9 seconds—an impressive but underwhelming 1.8% improvement. Nonetheless, this illustrates that even small tweaks can lead to tangible outcomes.
00:15:43.790 Even if just a minor improvement, I associated closely with those moments—seeing the homeless person who appeared to effortlessly glide by effortlessly. This metaphor encapsulates what Slo Mo represents. We didn’t achieve our initial goals, but we must keep gliding and digging deeper into performance metrics.
00:18:00.020 In that spirit, I decided to seek out the next most expensive operation within my performance data to find more low-hanging fruit. I took a closer look at my stack profile to discover where I could make further optimizations. This exploration led me to examine methods related to creating a digest from various data types, essentially streamlining the process and reducing overall checks and iterations involved, stressing the importance of minimizing unnecessary overheads.
00:20:15.579 Concerning this set of features, it is vital to prioritize identifying a goal - as Slow Mo sought a balance of minimal work and skating. For us, that means determining what we want to optimize. Gathering the right tools to assess performance is equally critical; tools like StackProf can greatly aid in analyzing time spend across operations.
00:22:11.710 After identifying the larger issues, we implemented measures that simplified numerous processes, transitioning from if-else constructs into hash structures, thereby reducing iteration time. The optimization led to a substantial reduction in benchmark execution time; from 14.9 seconds down to 12.5 seconds—a 16% improvement. Observing the patterns developing through this performance talk has been enlightening, continuously adapting to the evolving insights we uncover.
00:23:53.060 As I crafted this presentation, an interactive discussion with peers led to valuable feedback on how to handle object calls more efficiently in Ruby. It became clear that avoiding unnecessary scope lookups during method calls could also contribute significantly to performance optimization, leading to a proposal advocating for the integration of refinements for better code management.
00:25:45.210 This raised interesting conversations regarding how best to implement these optimizations within Ruby’s context without disrupting established practices. Engaging collaboratively with fellow Ruby enthusiasts at this conference—exploring innovative solutions—has been integral to advancing our collective prosperity as developers. Nevertheless, we cannot forget to examine personal coding habits as we foster an inclination toward continuous improvements in code performance.
00:27:39.060 Our key takeaway here is not just measuring performance in isolation but fostering a broader understanding of how all these factors interact to affect our overall coding efficiency. Breathing and stepping back to assess what matters in our workflows ultimately leads us towards meaningful advancements in our processes. Sustaining a positive growth trajectory is central to innovation in programming.
00:28:32.660 As we examine the depths of our disciplines, recall the camaraderie fostered by shared interests and values extend beyond merely improving code speed—it also encourages new ways of thinking and collaborating to make our work lives fulfilling. So take a deep breath, relax, and be reminded that performance improvement is a journey, not merely a destination; contribute to the atmosphere at RubyConf, where information, empathy, and insights interchange vigorously!
00:30:06.660 In closing, I want to reiterate: don’t be embarrassed by the programming language you love. Ruby is evolving, and year-on-year we see improvements in optimizing its capabilities. As we continue to push boundaries, take this opportunity to commit yourselves to mastering Ruby, honing your skills, and striving to make code better. Ultimately, regulate your pace; meet your personal development goals and embrace every moment you engage in your programming journey.
00:31:50.670 Now, how do I practically apply some of these lessons? The roadmap toward improved performance translates to identifying specific areas for optimization, knowing that Sprockets relies heavily on its cache mechanisms. Another way to enhance compile times involves utilizing cache optimizations, particularly when dealing with large applications. Adding tools like Bootscale actively aids in speeding up the loading processes, allowing seamless transitions between functionalities.
00:32:58.770 Our aim is to recognize the power of lower-level languages where applicable—integrating them into existing Ruby projects without overhauling the primary components. Exploring the use of JRuby or alternative languages like Rust or Go demonstrates that deploying these strategies encourages programming versatility. By adopting this mindset, consider how to appropriately apply integrated solutions, allowing you to reimagine development efforts while paving the way for exemplary programming practices.
00:34:28.330 Thank you all for attending—embrace performance as a joyful pursuit, connect with fellow enthusiasts, and remember that as programmers, we can strive for excellence, innovatively engage with our code, and push the horizons of Ruby programming further than ever.
00:35:30.160 Now, I see we have a question segment. Please feel free to engage. I’m open to discussing any inquiries you may have—whether it's about the film shot location or performance optimization particulars, I look forward to hearing what’s on your mind. Let's embrace this collaborative spirit and keep the conversation flowing.
00:36:37.320 If anyone is curious about where the movie was filmed, I believe it was shot in Venice, California. As for other questions—about refinement, optimizations, or Sprockets—I remain deeply engaged as we explore solutions. I also undertook substantial benchmarking to convert slow processes in JRuby and am actively looking for ways to revolve around potential enhancements.
00:38:12.790 Lastly, addressing the future directions of Sprockets within Ruby’s ecosystem, I can confidently assert that while we’ve faced resistance and challenges, Sprockets continues to thrive within legacy apps. Continuous refinements inform better pathways forward; more than ever, we must ponder the communal discussions surrounding optimal programming solutions and incorporate those reflections into our everyday practices.
00:39:35.540 Thank you all for coming and for your thoughtful engagement you shared throughout this talk. Remember, as we dive into the continuation of our goals in programming, embracing the collective effort is paramount for advancement and represents the ongoing journey we embark upon together. Until our next interaction—happy coding!