How to profile your Rails and Ruby applications with ruby-prof
Installing ruby-prof
First install ruby-prof:
1 git clone git://github.com/jeremy/ruby-prof.git 2 cd ruby-prof/ 3 rake gem 4 sudo gem install pkg/ruby-prof-0.6.1.gem
Note that version 0.6.0 doesn’t work, at least not with Rails 2.1.1. With 0.6.0 I got this message:
1 `gem install ruby-prof` to use the profiler
Setting up a new environment for profiling
Create config/environments/profiling.rb:
1 config.cache_classes = true 2 config.action_controller.consider_all_requests_local = false 3 config.action_controller.perform_caching = true 4 config.action_view.cache_template_loading = true 5 6 #config.log_level = :debug
Add the new environment to database.yml. You might want to reuse the development database.
Creating a profiling script
Next we’ll create a script that simply fetches the homepage, save the following code in profiling/homepage.rb:
1 get '/' 2 say "GET / => #{path}"
Run the script
Now run the script 100 times:
1 RAILS_ENV=profiling ./script/performance/request -n 100 profiling/homepage.rb
Profiling plain Ruby applications
You can also profile a block of code by calling RubyProf from your code:
1 require 'ruby-prof' 2 3 # Profile the code 4 RubyProf.start 5 ... 6 [code to profile] 7 ... 8 results = RubyProf.stop 9 10 File.open "#{RAILS_ROOT}/tmp/profile-graph.html", 'w' do |file| 11 RubyProf::GraphHtmlPrinter.new(results).print(file) 12 end 13 14 File.open "#{RAILS_ROOT}/tmp/profile-flat.txt", 'w' do |file| 15 RubyProf::FlatPrinter.new(results).print(file) 16 end 17 18 File.open "#{RAILS_ROOT}/tmp/profile-tree.prof", 'w' do |file| 19 RubyProf::CallTreePrinter.new(results).print(file) 20 end
Analyzing results
I prefer to use the RubyProf::CallTreePrinter to output data that kcachegrind can read. The HTML and text data is difficult to read so kcachegrind will definitely make your life easier.
On OSX you can install kcachegrind with Fink (or DarwinPorts):
1 sudo apt-get update ; sudo apt-get install fink 2 sudo apt-get install kcachegrind
There’s also WinCacheGrind and MacCacheGrind, but I haven’t tried those.
How to benchmark your Ruby code
You can easily benchmark your Ruby code like this:
1 require 'benchmark' 2 seconds = Benchmark.realtime do 3 sleep 1 4 end 5 print "#{seconds} elapsed..."
The output should be close to 1 second.