Debugging performance issues in your Rails app can be a tough challenge.
To get more detailed insights consider using the rack-mini-profiler Show archive.org snapshot gem.
Setup with Unpoly
Add the following gems:
group :development do
gem 'memory_profiler'
gem 'rack-mini-profiler'
gem 'stackprof'
end
Unpoly will interfere with the rack-mini-profiler widget, but configuring the following works okayish:
// rack-mini-profiler + unpoly
if (process.env.NODE_ENV === 'development') {
// disable unpoly for links in the profiler
up.link.config.noFollowSelectors.push('.profiler-results a')
document.addEventListener('up:link:follow', () => {
if (window.MiniProfiler !== undefined) {
window.MiniProfiler.pageTransition()
}
})
}
# config/initializers/rack_mini_profiler.rb
if Rails.env.development?
Rails.application.config.to_prepare do
Rack::MiniProfiler.config.position = 'top-right' # positon widget top-right
Rack::MiniProfiler.config.skip_paths = [ # ignore most asset requests
%r(/system.*),
%r(/assets.*),
]
Rack::MiniProfiler.config.html_container = 'html' # avoid unpoly replacements
end
end
SQL
Rack-Mini-Profiler will give you a lot of detailed information about SQL queries happening on your page. You will spot N+1, unecessary and slow queries this way.
Flamegraphs
If you're wondering where most of your time is spent, consider generating a flamegraph.There are a lot of different config options, but appending ?pp=async-flamegraph&flamegraph_ignore_gc=true
to your URL will generate a readable flamegraph for this request, without garbage collector gaps. You can then open the flamegraph by clicking the widget and following the "flamegraph" link at the bottom of the request's page. Search for long method calls in the graph and consider fixing those.
Caution
The gem also allows displaying the flamegraph directly by appending
?pp=flamegraph&flamegraph_ignore_gc=true
. But if the controller doesn't explicitly call therender
method, the view rendering won't be part of the flamegraph and you will miss slow queries there. Use with caution.
Some potential wins
- If you have slow ActiveRecord queries, consider speeding those up.
- If you have slow views (Haml/Partials can be slow), consider caching them.
- Remove code & sql-queries that are not needed to render the page.
- Calling
to_a
blindly on scopes will always force to load records, this is almost always unnecessary and slow
Caveats
Your development environment is configured differently than your production environment. The closer your envs match when profiling, the more reliable are your profiler results.
Don't get lost on optimizations on pages nobody cares about. Find quick wins in the most visited and important sites, your customer will tell you which pages those are.
Warning
Don't write performance optimized code by default. Monitor performance in production, spot an issue, reproduce locally, fix it and then verify your fixes in production.