I want to improve performance of my app, and started reading http://guides.rubyonrails.org/performance_testing.html. My questions are at the end of this “how I started” speach.
So I started simple with
class BrowsingTest < ActionDispatch::PerformanceTest
self.profile_options = { :runs => 5, :metrics => [:wall_time, :process_time],
:output => 'tmp/performance', :formats => [:flat] }
def test_homepage
get '/'
end
end
the output of
bundle exec rake test:profile
in the terminal is
BrowsingTest#test_homepage (909 ms warmup)
wall_time: 341 ms
process_time: 517 ms
and in process_time flat file, it starts like that
Thread ID: 70299857145540
Total: 2.589931
%self total self wait child calls name
12.45 0.32 0.32 0.00 0.00 110 BasicObject#method_missing
10.59 0.28 0.27 0.00 0.01 415 Kernel#raise
7.79 0.20 0.20 0.00 0.00 1350 <Class::Dir>#[]
Not really knowing what to do with that, I started by looking for something that uses method_missing a lot. I found that a lib I’m using to convert metrics (Alchemist) does that and includes itself in the Numeric class.
Since the homepage doesn’t really need that, I just removed the lib and re-ran the profiling test.
This time I got the following
BrowsingTest#test_homepage (856 ms warmup)
wall_time: 321 ms
process_time: 482 ms
And the flat file didn’t have method_missing anymore
Thread ID: 70185893711560
Total: 2.420023
%self total self wait child calls name
12.05 0.29 0.29 0.00 0.00 5 ActionView::Base#helpers
8.32 0.20 0.20 0.00 0.00 1350 <Class::Dir>#[]
5.12 0.12 0.12 0.00 0.00 5925 String#gsub
I ran it a second time and got
BrowsingTest#test_homepage (856 ms warmup)
wall_time: 321 ms
process_time: 482 ms
Thread ID: 70231460630220
Total: 2.411142
%self total self wait child calls name
14.18 1.49 0.34 0.00 1.16 3265 Array#each
8.26 0.20 0.20 0.00 0.00 1350 <Class::Dir>#[]
4.94 0.12 0.12 0.00 0.00 205 Kernel#caller
So it seems that not using the library saves ~35ms process time, which seems pretty consistent with what the flat files said. I guess I should try to do something about that, especially since it seems to be called so often because of the Numeric inclusion.
Now here are my questions:
- Is it the right approach ? Is there a better way to start ?
- What’s the best way to pinpoint the class/method that’s degrading performance (next step for me would be to look for something using Dir, but there’s more than one places where it’s used)
- What is an acceptable process time ?
- I ran the test:profile several times in a row, and the self time for “String#gsub” went from 0.04 to 0.12. What could happen ?
Thanks!
I like how you got familiar with the tools and how to read the results. New Relic is great tool for monitoring this stuff, but so is request_log_analyzer if you don’t want to pay for new relic over the long haul.
Monitoring is important, so you know when a problem creeps up
-John McCaffrey