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 select adjacent rows (next and previous rows) with MySQL
I’ve now packaged this into a Rails plugin called has_adjacent_finders
Problem
Finding the next and previous product is a common task on, for example, e-commerce sites.
Let’s say we have a table containing data having the following IDs:
1 201 2 202 3 203 4 204 5 205 6 206 7 207 8 208
How do we get the rows adjacent to row 205? We can rely on MySQL sorting—the primary key in this case— so these two queries will do the job for us:
1 # Find previous row 2 select id from products where id < 205 order by id desc limit 1 3 4 # Find next row 5 select id from products where id > 205 order by id asc limit 1
The two queries will return 204 and 206 respectively. You can also use other columns, not just ID…
How to create and use MySQL stored procedures
This is a simple example of a MySQL stored procedure that has both an in and out parameter:
1 DELIMITER | 2 DROP PROCEDURE IF EXISTS category_for | 3 CREATE PROCEDURE category_for (product_id int, OUT r_category_id INT) 4 BEGIN 5 DECLARE category_id INT; 6 DECLARE products_cursor CURSOR FOR SELECT category_id FROM products where id = product_id; 7 OPEN products_cursor; 8 FETCH products_cursor INTO category_id; 9 CLOSE products_cursor; 10 SET r_category_id = category_id; 11 END | 12 DELIMITER ;
Note that we use ; inside the procedure so we have to set the delimiter to | temporarily.
To call the stored procedure use the following SQL commands:
1 CALL category_for(202, @category_id);
The @category_id session variable will now contain the procedure’s output:
1 select @category_id; 2 +-------+ 3 | @category_id | 4 +-------+ 5 | 3 | 6 +-------+
How to convert a string to a timestamp and then back to a string with PHP
1 $r = date_parse("8:16:12 01.02.2008"); 2 $d = mktime($r['hour'], $r['minute'], $r['second'], $r['month'], $r['day'], $r['year']); 3 echo date("H:i:s d.m.Y", $d);
Prints out the following:
1 8:16:12 01.02.2008
How to backup ActiveRecord model data to YAML with ar_fixtures
First install the plugin:
1 script/plugin install http://github.com/mileszs/ar_fixtures/commits/master
Then dump data for all models with:
1 rake db:data:dump:all
There’s a task for loading the data into the database, see rake -T for more information.