Loading…
How to Fix Slow Code in Ruby
2023-10-18
- Source
- Shopify
- Published
- Added to Yomu
Summary
Performance regressions can accumulate in a large monolithic Rails application, making it difficult to identify offending changes among thousands of daily commits. The post presents profiling and benchmarking as complementary practices: profiling locates runtime bottlenecks, while benchmarking compares code paths and validates fixes. It covers elapsed time, CPU versus wall time, object allocations, TracePoint and ObjectSpace, plus rbspy, stackprof, rack-mini-profiler, and App Profiler, which supports on-demand remote production profiling at Shopify. A flamegraph example showed garbage collection consuming about 35% of CPU time in a slow request, and the team inferred excessive Ruby object allocation; a Rails benchmark showed roughly 50x improvement from caching an order’s total price calculation. The discussion cautions against micro-optimizations whose gains do not justify code changes and recommends addressing larger performance issues first.
Context
In a large monolithic Rails application with many independently working teams and thousands of daily commits, inefficiencies can accumulate into performance regressions that are difficult to trace to specific changes. The post addresses how to find slow code and prove that a fix is faster.
Approach / What changed
Use runtime profiling to locate bottlenecks and inspect elapsed time, CPU or wall time, and object allocations, with tools including rbspy, stackprof, rack-mini-profiler, and App Profiler. Use Ruby and Rails benchmarks, including benchmark-ips and Rails’s benchmark generator, to compare implementations and validate performance changes.
Takeaways
- Profiling can expose runtime problems that code review or static analysis may miss, including excessive object allocation and garbage-collection overhead.
- Ruby’s Benchmark module distinguishes user, system, total, and real time; bmbm adds a rehearsal run to prime caches or similar mechanisms before measurement.
- A Rails benchmark showed about a 50x improvement when an order’s total-price calculation was cached, while the post warns that tiny micro-optimizations may not justify their code changes.