From 9cffd6f842c0dc25ad19df04e97e630fac75f287 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 10 Jan 2009 00:32:22 +0000 Subject: More refactoring in perf guide --- railties/doc/guides/html/performance_testing.html | 263 +++++++++++---------- railties/doc/guides/source/performance_testing.txt | 187 ++++++++------- 2 files changed, 233 insertions(+), 217 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/performance_testing.html b/railties/doc/guides/html/performance_testing.html index a13c547849..aafb904f32 100644 --- a/railties/doc/guides/html/performance_testing.html +++ b/railties/doc/guides/html/performance_testing.html @@ -198,29 +198,29 @@ ul#navMain { -

3.3.2. Profiling

+

1.4.2. Profiling

Command line

This is the very basic form of output in profiling mode. Example :

@@ -470,22 +430,23 @@ http://www.gnu.org/software/src-highlite -->

Graph output shows how long each method takes to run, which methods call it and which methods it calls. Check ruby prof documentation for a better explaination.

Tree

Tree output is profiling information in calltree format for use by kcachegrind and similar tools.

-

3.4. Preparing Ruby and Ruby-prof

-

Before we go ahead, Rails performance testing requires you to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time. This process is very straight forward. If you’ve never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory:

-

3.4.1. Compile

+

1.5. Installing GC Patched Ruby

+

To get the best from Rails performance test cases, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation profiling. This process is very straight forward. If you’ve never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory:

+

1.5.1. Compile

+

Compile Ruby and apply this GC Patch:

[lifo@null ~]$ mkdir rubygc
-[lifo@null ~]$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p111.tar.gz
-[lifo@null ~]$ tar -xzvf ruby-1.8.6-p111.tar.gz
-[lifo@null ~]$ cd ruby-1.8.6-p111
-[lifo@null ruby-1.8.6-p111]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0
-[lifo@null ruby-1.8.6-p111]$ ./configure --prefix=/Users/lifo/rubygc
-[lifo@null ruby-1.8.6-p111]$ make && make install
-

3.4.2. Prepare aliases

+[lifo@null ~]$ wget <download the latest stable ruby from ftp://ftp.ruby-lang.org/pub/ruby> +[lifo@null ~]$ tar -xzvf <ruby-version.tar.gz> +[lifo@null ~]$ cd <ruby-version> +[lifo@null ruby-version]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0 +[lifo@null ruby-version]$ ./configure --prefix=/Users/lifo/rubygc +[lifo@null ruby-version]$ make && make install
+

1.5.2. Prepare aliases

Add the following lines in your ~/.profile for convenience:

@@ -495,51 +456,107 @@ alias gcgem='/Users/lifo/rubygc/bin/gem' alias gcirb='/Users/lifo/rubygc/bin/irb' alias gcrails='/Users/lifo/rubygc/bin/rails'
-

3.4.3. Install rubygems and some basic gems

-

Download Rubygems and install it from source. Afterwards, install rake. rails, ruby-prof and rack gems:

+

1.5.3. Install rubygems and some basic gems

+

Download Rubygems and install it from source. Rubygem’s README file should have necessary installation instructions.

+

Additionally, installa the following gems :

+
+

If installing mysql fails, you can try to install it manually:

-
[lifo@null ~]$ gcgem install rake
-[lifo@null ~]$ gcgem install rails
-[lifo@null ~]$ gcgem install ruby-prof
-[lifo@null ~]$ gcgem install rack
+
[lifo@null mysql]$ gcruby extconf.rb --with-mysql-config
+[lifo@null mysql]$ make && make install
-

3.4.4. Install MySQL gem

+

And you’re ready to go. Don’t forget to use gcruby and gcrake aliases when running performance tests!

+ +

2. Using and understanding the log files

+
+

Rails logs files containt basic but very useful information about the time taken to serve every request. A typical log entry looks something like :

-
-
[lifo@null ~]$ gcgem install mysql
-
-

If this fails, you can try to install it manually:

+
+
Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET]
+Rendering template within layouts/items
+Rendering items/index
+Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
+

For this section, we’re only interested in the last line from that log entry:

-
-
[lifo@null ~]$ cd /Users/lifo/rubygc/lib/ruby/gems/1.8/gems/mysql-2.7/
-[lifo@null mysql-2.7]$ gcruby extconf.rb --with-mysql-config
-[lifo@null mysql-2.7]$ make && make install
-
-

3.5. Generating performance test

-

Rails provides a generator for creating new performance tests:

+
+
Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
+

This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

+ +

3. Helper methods

+
+

Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a specific code. The method is called benchmark() in all three components.

-
[lifo@null application (master)]$ script/generate performance_test homepage
-

This will generate test/performance/homepage_test.rb:

+
Project.benchmark("Creating project") do
+  project = Project.create("name" => "stuff")
+  project.create_manager("name" => "David")
+  project.milestones << Milestone.find(:all)
+end
+

The above code benchmarks the multiple statments enclosed inside Project.benchmark("Creating project") do..end block and prints the results inside log files. The statement inside log files will look like:

-
require 'test_helper'
-require 'performance_test_help'
-
-class HomepageTest < ActionController::PerformanceTest
-  # Replace this with your real tests.
-  def test_homepage
-    get '/'
+
Creating projectem (185.3ms)
+

Please refer to API docs for optional options to benchmark()

+

Similarly, you could use this helper method inside controllers ( Note that it’s a class method here ):

+
+
+
def process_projects
+  self.class.benchmark("Processing projects") do
+    Project.process(params[:project_ids])
+    Project.update_cached_projects
   end
 end
-

Which you can modify to suit your needs.

+

and views:

+
+
+
<% benchmark("Showing projects partial") do %>
+  <%= render :partial => @projects %>
+<% end %>

4. Other Profiling Tools

diff --git a/railties/doc/guides/source/performance_testing.txt b/railties/doc/guides/source/performance_testing.txt index b741ddfd00..7df384c7af 100644 --- a/railties/doc/guides/source/performance_testing.txt +++ b/railties/doc/guides/source/performance_testing.txt @@ -1,7 +1,7 @@ Performance testing Rails Applications ====================================== -This guide covers the benchmarking and profiling tactics/tools of Rails and Ruby in general. By referring to this guide, you will be able to: +This guide covers the various ways of performance testing a Ruby on Rails application. By referring to this guide, you will be able to: * Understand the various types of benchmarking and profiling metrics * Generate performance/benchmarking tests @@ -11,90 +11,52 @@ This guide covers the benchmarking and profiling tactics/tools of Rails and Ruby Performance testing is an integral part of the development cycle. It is very important that you don't make your end users wait for too long before the page is completely loaded. Ensuring a plesant browsing experience to the end users and cutting cost of unnecessary hardwares is important for any web application. -== Using and understanding the log files == - -Rails logs files containt basic but very useful information about the time taken to serve every request. A typical log entry looks something like : +== Performance Test Cases == -[source, ruby] ----------------------------------------------------------------------------- -Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET] -Rendering template within layouts/items -Rendering items/index -Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ----------------------------------------------------------------------------- +Rails performance tests are integration tests designed for benchmarking and profiling the test code. With performance tests, you can determine where your application's memory or speed problems are coming from, and get a more in-depth picture of those problems. -For this section, we're only interested in the last line from that log entry: +In a freshly generated Rails application, +test/performance/browsing_test.rb+ contains an example of a performance test: [source, ruby] ---------------------------------------------------------------------------- -Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ----------------------------------------------------------------------------- - -This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. - -== Helper methods == - -Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a specific code. The method is called +benchmark()+ in all three components. +require 'test_helper' +require 'performance_test_help' -[source, ruby] ----------------------------------------------------------------------------- -Project.benchmark("Creating project") do - project = Project.create("name" => "stuff") - project.create_manager("name" => "David") - project.milestones << Milestone.find(:all) +# Profiling results for each test method are written to tmp/performance. +class BrowsingTest < ActionController::PerformanceTest + def test_homepage + get '/' + end end ---------------------------------------------------------------------------- -The above code benchmarks the multiple statments enclosed inside +Project.benchmark("Creating project") do..end+ block and prints the results inside log files. The statement inside log files will look like: - -[source, ruby] ----------------------------------------------------------------------------- -Creating projectem (185.3ms) ----------------------------------------------------------------------------- +The above example is a simple performance test case for profiling a GET request to the application's homepage. -Please refer to http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001336[API docs] for optional options to +benchmark()+ +=== Generating performance tests === -Similarly, you could use this helper method inside http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[controllers] ( Note that it's a class method here ): +Rails provides a generator called +performance_test+ for creating new performance tests: -[source, ruby] ----------------------------------------------------------------------------- -def process_projects - self.class.benchmark("Processing projects") do - Project.process(params[:project_ids]) - Project.update_cached_projects - end -end ----------------------------------------------------------------------------- - -and http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[views]: - -[source, ruby] +[source, shell] ---------------------------------------------------------------------------- -<% benchmark("Showing projects partial") do %> - <%= render :partial => @projects %> -<% end %> +[lifo@null application (master)]$ script/generate performance_test homepage ---------------------------------------------------------------------------- -== Performance Test Cases == - -Rails provides a very easy way to write performance test cases, which look just like the regular integration tests. Performance tests run a code profiler on your test methods. Profiling output for combinations of each test method, measurement, and output format are written to your +tmp/performance+ directory. By default, process_time is measured and both flat and graph_html output formats are written, so you'll have two output files per test method. - -If you have a look at +test/performance/browsing_test.rb+ in a newly created Rails application: +This will generate +test/performance/homepage_test.rb+: [source, ruby] ---------------------------------------------------------------------------- require 'test_helper' require 'performance_test_help' -# Profiling results for each test method are written to tmp/performance. -class BrowsingTest < ActionController::PerformanceTest +class HomepageTest < ActionController::PerformanceTest + # Replace this with your real tests. def test_homepage get '/' end end ---------------------------------------------------------------------------- -This is an automatically generated example performance test file, for testing performance of homepage('/') of the application. +Which you can modify to suit your needs. === Modes === @@ -138,25 +100,25 @@ Mode : Profiling Measures the amount of memory used for the performance test case. -Mode : Benchmarking, Profiling [Requires specially compiled Ruby] +Mode : Benchmarking, Profiling [xref:gc[Requires GC Patched Ruby]] ==== Objects ==== Measures the number of objects allocated for the performance test case. -Mode : Benchmarking, Profiling [Requires specially compiled Ruby] +Mode : Benchmarking, Profiling [xref:gc[Requires GC Patched Ruby]] ==== GC Runs ==== Measures the number of times GC was invoked for the performance test case. -Mode : Benchmarking [Requires specially compiled Ruby] +Mode : Benchmarking [xref:gc[Requires GC Patched Ruby]] ==== GC Time ==== Measures the amount of time spent in GC for the performance test case. -Mode : Benchmarking [Requires specially compiled Ruby] +Mode : Benchmarking [xref:gc[Requires GC Patched Ruby]] === Understanding the output === @@ -235,21 +197,24 @@ Graph output shows how long each method takes to run, which methods call it and Tree output is profiling information in calltree format for use by kcachegrind and similar tools. -=== Preparing Ruby and Ruby-prof === +[[gc]] +=== Installing GC Patched Ruby === -Before we go ahead, Rails performance testing requires you to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time. This process is very straight forward. If you've never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory: +To get the best from Rails performance test cases, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation profiling. This process is very straight forward. If you've never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory: ==== Compile ==== +Compile Ruby and apply this http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch[GC Patch]: + [source, shell] ---------------------------------------------------------------------------- [lifo@null ~]$ mkdir rubygc -[lifo@null ~]$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p111.tar.gz -[lifo@null ~]$ tar -xzvf ruby-1.8.6-p111.tar.gz -[lifo@null ~]$ cd ruby-1.8.6-p111 -[lifo@null ruby-1.8.6-p111]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0 -[lifo@null ruby-1.8.6-p111]$ ./configure --prefix=/Users/lifo/rubygc -[lifo@null ruby-1.8.6-p111]$ make && make install +[lifo@null ~]$ wget +[lifo@null ~]$ tar -xzvf +[lifo@null ~]$ cd +[lifo@null ruby-version]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0 +[lifo@null ruby-version]$ ./configure --prefix=/Users/lifo/rubygc +[lifo@null ruby-version]$ make && make install ---------------------------------------------------------------------------- ==== Prepare aliases ==== @@ -266,54 +231,88 @@ alias gcrails='/Users/lifo/rubygc/bin/rails' ==== Install rubygems and some basic gems ==== -Download http://rubyforge.org/projects/rubygems[Rubygems] and install it from source. Afterwards, install rake. rails, ruby-prof and rack gems: +Download http://rubyforge.org/projects/rubygems[Rubygems] and install it from source. Rubygem's README file should have necessary installation instructions. + +Additionally, installa the following gems : + + * +rake+ + * +rails+ + * +ruby-prof+ + * +rack+ + * +mysql+ + +If installing +mysql+ fails, you can try to install it manually: ---------------------------------------------------------------------------- -[lifo@null ~]$ gcgem install rake -[lifo@null ~]$ gcgem install rails -[lifo@null ~]$ gcgem install ruby-prof -[lifo@null ~]$ gcgem install rack +[lifo@null mysql]$ gcruby extconf.rb --with-mysql-config +[lifo@null mysql]$ make && make install ---------------------------------------------------------------------------- -==== Install MySQL gem ==== +And you're ready to go. Don't forget to use +gcruby+ and +gcrake+ aliases when running performance tests! + +== Using and understanding the log files == + +Rails logs files containt basic but very useful information about the time taken to serve every request. A typical log entry looks something like : +[source, ruby] ---------------------------------------------------------------------------- -[lifo@null ~]$ gcgem install mysql +Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET] +Rendering template within layouts/items +Rendering items/index +Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ---------------------------------------------------------------------------- -If this fails, you can try to install it manually: +For this section, we're only interested in the last line from that log entry: +[source, ruby] ---------------------------------------------------------------------------- -[lifo@null ~]$ cd /Users/lifo/rubygc/lib/ruby/gems/1.8/gems/mysql-2.7/ -[lifo@null mysql-2.7]$ gcruby extconf.rb --with-mysql-config -[lifo@null mysql-2.7]$ make && make install +Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ---------------------------------------------------------------------------- -=== Generating performance test === +This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. -Rails provides a generator for creating new performance tests: +== Helper methods == -[source, shell] +Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a specific code. The method is called +benchmark()+ in all three components. + +[source, ruby] ---------------------------------------------------------------------------- -[lifo@null application (master)]$ script/generate performance_test homepage +Project.benchmark("Creating project") do + project = Project.create("name" => "stuff") + project.create_manager("name" => "David") + project.milestones << Milestone.find(:all) +end ---------------------------------------------------------------------------- -This will generate +test/performance/homepage_test.rb+: +The above code benchmarks the multiple statments enclosed inside +Project.benchmark("Creating project") do..end+ block and prints the results inside log files. The statement inside log files will look like: [source, ruby] ---------------------------------------------------------------------------- -require 'test_helper' -require 'performance_test_help' +Creating projectem (185.3ms) +---------------------------------------------------------------------------- -class HomepageTest < ActionController::PerformanceTest - # Replace this with your real tests. - def test_homepage - get '/' +Please refer to http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001336[API docs] for optional options to +benchmark()+ + +Similarly, you could use this helper method inside http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[controllers] ( Note that it's a class method here ): + +[source, ruby] +---------------------------------------------------------------------------- +def process_projects + self.class.benchmark("Processing projects") do + Project.process(params[:project_ids]) + Project.update_cached_projects end end ---------------------------------------------------------------------------- -Which you can modify to suit your needs. +and http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[views]: + +[source, ruby] +---------------------------------------------------------------------------- +<% benchmark("Showing projects partial") do %> + <%= render :partial => @projects %> +<% end %> +---------------------------------------------------------------------------- == Other Profiling Tools == @@ -332,4 +331,4 @@ http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/4[Lighthouse * January 9, 2009: Rewrite by Pratik * October 17, 2008: First revision by Pratik -* September 6, 2008: Initial version by Matthew Bergman \ No newline at end of file +* September 6, 2008: Initial version by Matthew Bergman -- cgit v1.2.3 From 8342174b2800937024a06273d1891730e6cf02cc Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 10 Jan 2009 01:10:30 +0000 Subject: Keep movin stuff in perf guide --- railties/doc/guides/html/performance_testing.html | 65 +++++++++------- railties/doc/guides/source/performance_testing.txt | 86 ++++++++++++++-------- 2 files changed, 94 insertions(+), 57 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/performance_testing.html b/railties/doc/guides/html/performance_testing.html index aafb904f32..4a4d15eac6 100644 --- a/railties/doc/guides/html/performance_testing.html +++ b/railties/doc/guides/html/performance_testing.html @@ -215,10 +215,19 @@ ul#navMain {
  • - Using and understanding the log files + Helper methods +
  • - Helper methods + Request Logging
  • Other Profiling Tools @@ -494,30 +503,10 @@ alias gcrails='/Users/lifo/rubygc/bin/rails'
  • And you’re ready to go. Don’t forget to use gcruby and gcrake aliases when running performance tests!

    -

    2. Using and understanding the log files

    -
    -

    Rails logs files containt basic but very useful information about the time taken to serve every request. A typical log entry looks something like :

    -
    -
    -
    Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET]
    -Rendering template within layouts/items
    -Rendering items/index
    -Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
    -

    For this section, we’re only interested in the last line from that log entry:

    -
    -
    -
    Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
    -

    This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

    -
    -

    3. Helper methods

    +

    2. Helper methods

    Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a specific code. The method is called benchmark() in all three components.

    +

    2.1. Model

    project.create_manager("name" => "David") project.milestones << Milestone.find(:all) end
    -

    The above code benchmarks the multiple statments enclosed inside Project.benchmark("Creating project") do..end block and prints the results inside log files. The statement inside log files will look like:

    +

    The above code benchmarks the multiple statments enclosed inside Project.benchmark("Creating project") do..end block and prints the results to the log file. The statement inside log files will look like:

    Creating projectem (185.3ms)

    Please refer to API docs for optional options to benchmark()

    +

    2.2. Controller

    Similarly, you could use this helper method inside controllers ( Note that it’s a class method here ):

    Project.update_cached_projects end end
    -

    and views:

    +

    2.3. View

    +

    And in views:

    <%= render :partial => @projects %> <% end %>
    +

    3. Request Logging

    +
    +

    Rails log files containt basic but very useful information about the time taken to serve each request. A typical log entry looks something like :

    +
    +
    +
    Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET]
    +Rendering template within layouts/items
    +Rendering items/index
    +Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
    +

    For this section, we’re only interested in the last line from that log entry:

    +
    +
    +
    Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
    +

    This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

    +

    Michael Koziarski has an interesting blog post explaining the importance of using milliseconds as the metric.

    +

    4. Other Profiling Tools

      diff --git a/railties/doc/guides/source/performance_testing.txt b/railties/doc/guides/source/performance_testing.txt index 7df384c7af..f42b3686b7 100644 --- a/railties/doc/guides/source/performance_testing.txt +++ b/railties/doc/guides/source/performance_testing.txt @@ -202,31 +202,47 @@ Tree output is profiling information in calltree format for use by kcachegrind a To get the best from Rails performance test cases, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation profiling. This process is very straight forward. If you've never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory: -==== Compile ==== +==== Instllation ==== Compile Ruby and apply this http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch[GC Patch]: +==== Download and Extract ==== + [source, shell] ---------------------------------------------------------------------------- [lifo@null ~]$ mkdir rubygc [lifo@null ~]$ wget [lifo@null ~]$ tar -xzvf [lifo@null ~]$ cd +---------------------------------------------------------------------------- + +==== Apply the patch ==== + +[source, shell] +---------------------------------------------------------------------------- [lifo@null ruby-version]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0 -[lifo@null ruby-version]$ ./configure --prefix=/Users/lifo/rubygc +---------------------------------------------------------------------------- + +==== Configure and Install ==== + +The following will install ruby in your home directory's +/rubygc+ directory. Make sure to replace ++ with a full patch to your actual home directory. + +[source, shell] +---------------------------------------------------------------------------- +[lifo@null ruby-version]$ ./configure --prefix=//rubygc [lifo@null ruby-version]$ make && make install ---------------------------------------------------------------------------- ==== Prepare aliases ==== -Add the following lines in your ~/.profile for convenience: +For convenience, add the following lines in your ~/.profile after replacing with your : ---------------------------------------------------------------------------- -alias gcruby='/Users/lifo/rubygc/bin/ruby' -alias gcrake='/Users/lifo/rubygc/bin/rake' -alias gcgem='/Users/lifo/rubygc/bin/gem' -alias gcirb='/Users/lifo/rubygc/bin/irb' -alias gcrails='/Users/lifo/rubygc/bin/rails' +alias gcruby='~/rubygc/bin/ruby' +alias gcrake='~/rubygc/bin/rake' +alias gcgem='~/rubygc/bin/gem' +alias gcirb='~/rubygc/bin/irb' +alias gcrails='~/rubygc/bin/rails' ---------------------------------------------------------------------------- ==== Install rubygems and some basic gems ==== @@ -250,31 +266,12 @@ If installing +mysql+ fails, you can try to install it manually: And you're ready to go. Don't forget to use +gcruby+ and +gcrake+ aliases when running performance tests! -== Using and understanding the log files == - -Rails logs files containt basic but very useful information about the time taken to serve every request. A typical log entry looks something like : - -[source, ruby] ----------------------------------------------------------------------------- -Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET] -Rendering template within layouts/items -Rendering items/index -Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ----------------------------------------------------------------------------- - -For this section, we're only interested in the last line from that log entry: - -[source, ruby] ----------------------------------------------------------------------------- -Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ----------------------------------------------------------------------------- - -This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. - == Helper methods == Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a specific code. The method is called +benchmark()+ in all three components. +=== Model === + [source, ruby] ---------------------------------------------------------------------------- Project.benchmark("Creating project") do @@ -284,7 +281,7 @@ Project.benchmark("Creating project") do end ---------------------------------------------------------------------------- -The above code benchmarks the multiple statments enclosed inside +Project.benchmark("Creating project") do..end+ block and prints the results inside log files. The statement inside log files will look like: +The above code benchmarks the multiple statments enclosed inside +Project.benchmark("Creating project") do..end+ block and prints the results to the log file. The statement inside log files will look like: [source, ruby] ---------------------------------------------------------------------------- @@ -293,6 +290,8 @@ Creating projectem (185.3ms) Please refer to http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001336[API docs] for optional options to +benchmark()+ +=== Controller === + Similarly, you could use this helper method inside http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[controllers] ( Note that it's a class method here ): [source, ruby] @@ -305,7 +304,9 @@ def process_projects end ---------------------------------------------------------------------------- -and http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[views]: +=== View === + +And in http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethods.html#M000715[views]: [source, ruby] ---------------------------------------------------------------------------- @@ -314,6 +315,29 @@ and http://api.rubyonrails.com/classes/ActionController/Benchmarking/ClassMethod <% end %> ---------------------------------------------------------------------------- +== Request Logging == + +Rails log files containt basic but very useful information about the time taken to serve each request. A typical log entry looks something like : + +[source, ruby] +---------------------------------------------------------------------------- +Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET] +Rendering template within layouts/items +Rendering items/index +Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] +---------------------------------------------------------------------------- + +For this section, we're only interested in the last line from that log entry: + +[source, ruby] +---------------------------------------------------------------------------- +Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] +---------------------------------------------------------------------------- + +This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. + +Michael Koziarski has an http://www.therailsway.com/2009/1/6/requests-per-second[interesting blog post] explaining the importance of using milliseconds as the metric. + == Other Profiling Tools == * http://www.hpl.hp.com/research/linux/httperf/[httperf] -- cgit v1.2.3 From 190eb9b07f3f48d07137b25c11dca99b40fd72b1 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 10 Jan 2009 02:56:14 +0000 Subject: Some examples for perf testing --- railties/doc/guides/html/performance_testing.html | 164 +++++++++++++++++---- railties/doc/guides/source/performance_testing.txt | 99 ++++++++++++- 2 files changed, 231 insertions(+), 32 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/performance_testing.html b/railties/doc/guides/html/performance_testing.html index 4a4d15eac6..dbbd52fa2b 100644 --- a/railties/doc/guides/html/performance_testing.html +++ b/railties/doc/guides/html/performance_testing.html @@ -2,7 +2,7 @@ - Performance testing Rails Applications + Performance Testing Rails Applications @@ -204,6 +204,8 @@ ul#navMain {
    • Generating performance tests
    • +
    • Examples
    • +
    • Modes
    • Metrics
    • @@ -233,7 +235,7 @@ ul#navMain { Other Profiling Tools
    • - Commercial products dedicated to Rails Perfomance + Commercial products
    • Changelog @@ -242,7 +244,7 @@ ul#navMain {
    -

    Performance testing Rails Applications

    +

    Performance Testing Rails Applications

    This guide covers the various ways of performance testing a Ruby on Rails application. By referring to this guide, you will be able to:

    @@ -319,9 +321,96 @@ http://www.gnu.org/software/src-highlite --> end end

    Which you can modify to suit your needs.

    -

    1.2. Modes

    +

    1.2. Examples

    +

    Let’s assume your application have the following controller and model:

    +
    +
    +
    # routes.rb
    +map.root :controller => 'home'
    +map.resources :posts
    +
    +# home_controller.rb
    +class HomeController < ApplicationController
    +  def dashboard
    +    @users = User.last_ten(:include => :avatars)
    +    @posts = Post.all_today
    +  end
    +end
    +
    +# posts_controller.rb
    +class PostsController < ApplicationController
    +  def create
    +    @post = Post.create(params[:post])
    +    redirect_to(@post)
    +  end
    +end
    +
    +# post.rb
    +class Post < ActiveRecord::Base
    +  before_save :recalculate_costly_stats
    +
    +  def slow_method
    +    # I fire gallzilion queries sleeping all around
    +  end
    +
    +  private
    +
    +  def recalculate_costly_stats
    +    # CPU heavy calculations
    +  end
    +end
    +

    1.2.1. Controller Example

    +

    Performance tests are special kind of integration tests. This allows you to use get and post methods inside the performance tests.

    +

    Performance tests for the controller code above can be something like:

    +
    +
    +
    require 'test_helper'
    +require 'performance_test_help'
    +
    +class PostPerformanceTest < ActionController::PerformanceTest
    +  def setup
    +    # Application requires logged in user
    +    login_as(:lifo)
    +  end
    +
    +  def test_homepage
    +    get '/dashboard'
    +  end
    +
    +  def test_creating_new_post
    +    post '/posts', :post => { :body => 'lifo is fooling you' }
    +  end
    +end
    +

    You can find more details about get and post methods in API documentation of integration testing.

    +

    1.2.2. Model Example

    +

    Even though performance tests are integration tests and hence closer to request/response cycle by nature, it doesn’t prevent us from testing pure model code inside. Performance test for Post model above can be somewhat like:

    +
    +
    +
    require 'test_helper'
    +require 'performance_test_help'
    +
    +class PostModelTest < ActionController::PerformanceTest
    +  def test_creation
    +    Post.create :body => 'still fooling you', :cost => '100'
    +  end
    +
    +  def test_slow_method
    +    # Using posts(:awesome) fixture
    +    posts(:awesome).slow_method
    +  end
    +end
    +

    1.3. Modes

    Performance test cases can be run in two modes : Benchmarking and Profling.

    -

    1.2.1. Benchmarking

    +

    1.3.1. Benchmarking

    Benchmarking helps you find out how fast are your test cases. Each Test case is run 4 times in this mode. To run performance tests in benchmarking mode:

    $ rake test:benchmark
    -

    1.2.2. Profiling

    +

    1.3.2. Profiling

    Profiling helps introspect into your test cases and figure out which are the slow parts. Each Test case is run 1 time in this mode. To run performance tests in profiling mode:

    $ rake test:profile
    -

    1.3. Metrics

    +

    1.4. Metrics

    Benchmarking and profiling run performance test cases in various modes to help precisely figure out the where the problem lies.

    -

    1.3.1. Wall Time

    +

    1.4.1. Wall Time

    Measures the real world time elapsed during the test run. It is affected by any other processes concurrently running on the system.

    Mode : Benchmarking

    -

    1.3.2. Process Time

    +

    1.4.2. Process Time

    Measures the time taken by the process. It is unaffected by any other processes running concurrently on the same system. Hence, process time is likely to be constant for any given performance test, irrespective of the machine load.

    Mode : Profiling

    -

    1.3.3. Memory

    +

    1.4.3. Memory

    Measures the amount of memory used for the performance test case.

    Mode : Benchmarking, Profiling [Requires GC Patched Ruby]

    -

    1.3.4. Objects

    +

    1.4.4. Objects

    Measures the number of objects allocated for the performance test case.

    Mode : Benchmarking, Profiling [Requires GC Patched Ruby]

    -

    1.3.5. GC Runs

    +

    1.4.5. GC Runs

    Measures the number of times GC was invoked for the performance test case.

    Mode : Benchmarking [Requires GC Patched Ruby]

    -

    1.3.6. GC Time

    +

    1.4.6. GC Time

    Measures the amount of time spent in GC for the performance test case.

    Mode : Benchmarking [Requires GC Patched Ruby]

    -

    1.4. Understanding the output

    +

    1.5. Understanding the output

    Performance tests generate different outputs inside tmp/performance directory based on the mode it is run in and the metric.

    -

    1.4.1. Benchmarking

    +

    1.5.1. Benchmarking

    In benchmarking mode, performance tests generate two types of outputs :

    Command line

    This is the primary form of output in benchmarking mode. Example :

    @@ -421,7 +510,7 @@ http://www.gnu.org/software/src-highlite --> 0.00740450000000004,2009-01-09T03:54:47Z,,2.3.0.master.859e150,ruby-1.8.6.110,i686-darwin9.0.0 0.00603150000000008,2009-01-09T03:54:57Z,,2.3.0.master.859e150,ruby-1.8.6.111,i686-darwin9.1.0 0.00771250000000012,2009-01-09T15:46:03Z,,2.3.0.master.859e150,ruby-1.8.6.110,i686-darwin9.0.0
    -

    1.4.2. Profiling

    +

    1.5.2. Profiling

    Command line

    This is the very basic form of output in profiling mode. Example :

    @@ -439,10 +528,11 @@ http://www.gnu.org/software/src-highlite -->

    Graph output shows how long each method takes to run, which methods call it and which methods it calls. Check ruby prof documentation for a better explaination.

    Tree

    Tree output is profiling information in calltree format for use by kcachegrind and similar tools.

    -

    1.5. Installing GC Patched Ruby

    +

    1.6. Installing GC Patched Ruby

    To get the best from Rails performance test cases, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation profiling. This process is very straight forward. If you’ve never compiled a Ruby binary before, you can follow the following steps to build a ruby binary inside your home directory:

    -

    1.5.1. Compile

    +

    1.6.1. Instllation

    Compile Ruby and apply this GC Patch:

    +

    1.6.2. Download and Extract

    [lifo@null ~]$ mkdir rubygc
     [lifo@null ~]$ wget <download the latest stable ruby from ftp://ftp.ruby-lang.org/pub/ruby>
     [lifo@null ~]$ tar -xzvf <ruby-version.tar.gz>
    -[lifo@null ~]$ cd <ruby-version>
    -[lifo@null ruby-version]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0
    -[lifo@null ruby-version]$ ./configure --prefix=/Users/lifo/rubygc
    +[lifo@null ~]$ cd <ruby-version>
    +

    1.6.3. Apply the patch

    +
    +
    +
    [lifo@null ruby-version]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0
    +

    1.6.4. Configure and Install

    +

    The following will install ruby in your home directory’s /rubygc directory. Make sure to replace <homedir> with a full patch to your actual home directory.

    +
    +
    +
    [lifo@null ruby-version]$ ./configure --prefix=/<homedir>/rubygc
     [lifo@null ruby-version]$ make && make install
    -

    1.5.2. Prepare aliases

    -

    Add the following lines in your ~/.profile for convenience:

    +

    1.6.5. Prepare aliases

    +

    For convenience, add the following lines in your ~/.profile after replacing <username> with your :

    -
    alias gcruby='/Users/lifo/rubygc/bin/ruby'
    -alias gcrake='/Users/lifo/rubygc/bin/rake'
    -alias gcgem='/Users/lifo/rubygc/bin/gem'
    -alias gcirb='/Users/lifo/rubygc/bin/irb'
    -alias gcrails='/Users/lifo/rubygc/bin/rails'
    +
    alias gcruby='~/rubygc/bin/ruby'
    +alias gcrake='~/rubygc/bin/rake'
    +alias gcgem='~/rubygc/bin/gem'
    +alias gcirb='~/rubygc/bin/irb'
    +alias gcrails='~/rubygc/bin/rails'
    -

    1.5.3. Install rubygems and some basic gems

    +

    1.6.6. Install rubygems and some basic gems

    Download Rubygems and install it from source. Rubygem’s README file should have necessary installation instructions.

    Additionally, installa the following gems :

      @@ -591,8 +694,9 @@ http://www.gnu.org/software/src-highlite -->
    -

    5. Commercial products dedicated to Rails Perfomance

    +

    5. Commercial products

    +

    Rails has been lucky to have three startups dedicated to Rails specific performance tools:

    • diff --git a/railties/doc/guides/source/performance_testing.txt b/railties/doc/guides/source/performance_testing.txt index f42b3686b7..e58927b758 100644 --- a/railties/doc/guides/source/performance_testing.txt +++ b/railties/doc/guides/source/performance_testing.txt @@ -1,4 +1,4 @@ -Performance testing Rails Applications +Performance Testing Rails Applications ====================================== This guide covers the various ways of performance testing a Ruby on Rails application. By referring to this guide, you will be able to: @@ -58,6 +58,98 @@ end Which you can modify to suit your needs. +=== Examples === + +Let's assume your application have the following controller and model: + +[source, ruby] +---------------------------------------------------------------------------- +# routes.rb +map.root :controller => 'home' +map.resources :posts + +# home_controller.rb +class HomeController < ApplicationController + def dashboard + @users = User.last_ten(:include => :avatars) + @posts = Post.all_today + end +end + +# posts_controller.rb +class PostsController < ApplicationController + def create + @post = Post.create(params[:post]) + redirect_to(@post) + end +end + +# post.rb +class Post < ActiveRecord::Base + before_save :recalculate_costly_stats + + def slow_method + # I fire gallzilion queries sleeping all around + end + + private + + def recalculate_costly_stats + # CPU heavy calculations + end +end +---------------------------------------------------------------------------- + +==== Controller Example ==== + +Performance tests are special kind of integration tests. This allows you to use +get+ and +post+ methods inside the performance tests. + +Performance tests for the controller code above can be something like: + +[source, ruby] +---------------------------------------------------------------------------- +require 'test_helper' +require 'performance_test_help' + +class PostPerformanceTest < ActionController::PerformanceTest + def setup + # Application requires logged in user + login_as(:lifo) + end + + def test_homepage + get '/dashboard' + end + + def test_creating_new_post + post '/posts', :post => { :body => 'lifo is fooling you' } + end +end +---------------------------------------------------------------------------- + +You can find more details about +get+ and +post+ methods in API documentation of integration testing. + +==== Model Example ==== + +Even though performance tests are integration tests and hence closer to request/response cycle by nature, it doesn't prevent us from testing pure model code inside. Performance test for +Post+ model above can be somewhat like: + +[source, ruby] +---------------------------------------------------------------------------- +require 'test_helper' +require 'performance_test_help' + +class PostModelTest < ActionController::PerformanceTest + def test_creation + Post.create :body => 'still fooling you', :cost => '100' + end + + def test_slow_method + # Using posts(:awesome) fixture + posts(:awesome).slow_method + end +end +---------------------------------------------------------------------------- + === Modes === Performance test cases can be run in two modes : Benchmarking and Profling. @@ -344,7 +436,10 @@ Michael Koziarski has an http://www.therailsway.com/2009/1/6/requests-per-second * http://rails-analyzer.rubyforge.org/[Rails Analyzer] * http://www.flyingmachinestudios.com/projects/[Palmist] -== Commercial products dedicated to Rails Perfomance == +== Commercial products == + +Rails has been lucky to have three startups dedicated to Rails specific performance tools: + * http://www.newrelic.com[New Relic] * http://www.fiveruns.com[Fiveruns] * http://scoutapp.com[Scout] -- cgit v1.2.3 From 807c1e899d48e97318df7aab901cc1c1ee927292 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 10 Jan 2009 03:28:23 +0000 Subject: Minor changes in performance guide --- railties/doc/guides/html/index.html | 2 +- railties/doc/guides/html/performance_testing.html | 61 +++++++++++++--------- railties/doc/guides/source/index.txt | 2 +- railties/doc/guides/source/performance_testing.txt | 60 ++++++++++++--------- 4 files changed, 72 insertions(+), 53 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/index.html b/railties/doc/guides/html/index.html index b2dce5cd67..8dc8f6f95b 100644 --- a/railties/doc/guides/html/index.html +++ b/railties/doc/guides/html/index.html @@ -348,7 +348,7 @@ of your code.

    1. Performance Test Cases

    @@ -418,7 +418,7 @@ http://www.gnu.org/software/src-highlite --> end end

    1.3. Modes

    -

    Performance tests can be run in two modes : Benchmarking and Profling.

    +

    Performance tests can be run in two modes : Benchmarking and Profiling.

    1.3.1. Benchmarking

    Benchmarking helps find out how fast is a performance test. Each test case is run 4 times in benchmarking mode.

    To run performance tests in benchmarking mode:

    @@ -429,7 +429,7 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
    $ rake test:benchmark

    1.3.2. Profiling

    -

    Profiling helps you introspect into a performance test and provide an in-depth picture of the slow and memory hungy parts. Each Test case is run 1 time in profiling mode.

    +

    Profiling helps you introspect into a performance test and provide an in-depth picture of the slow and memory hungry parts. Each Test case is run 1 time in profiling mode.

    To run performance tests in profiling mode:

    memory: 832.13 KB objects: 7882
    Flat
    -

    Flat output shows the total amount of time spent in each method. Check ruby prof documentation for a better explaination.

    +

    Flat output shows the total amount of time spent in each method. Check ruby prof documentation for a better explanation.

    Graph
    -

    Graph output shows how long each method takes to run, which methods call it and which methods it calls. Check ruby prof documentation for a better explaination.

    +

    Graph output shows how long each method takes to run, which methods call it and which methods it calls. Check ruby prof documentation for a better explanation.

    Tree

    Tree output is profiling information in calltree format for use by kcachegrind and similar tools.

    1.6. Tuning Test Runs

    -

    By default, each performance test is run 4 times in benchmarking model and 1 time in profiling. However, test runs can easily be configured.

    +

    By default, each performance test is run 4 times in benchmarking mode and 1 time in profiling. However, test runs can easily be configured.

    - +
    @@ -552,7 +552,7 @@ http://www.gnu.org/software/src-highlite -->

    1.7. Installing GC Patched Ruby

    To get the best from Rails performance tests, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation.

    The process is fairly straight forward. If you’ve never compiled a Ruby binary before, follow the following steps to build a ruby binary inside your home directory:

    -

    1.7.1. Instllation

    +

    1.7.1. Installation

    Compile Ruby and apply this GC Patch:

    1.7.2. Download and Extract

    @@ -592,7 +592,7 @@ alias gcrails='~/rubygc/bin/rails'

    1.7.6. Install rubygems and dependency gems

    Download Rubygems and install it from source. Rubygem’s README file should have necessary installation instructions.

    -

    Additionally, installa the following gems :

    +

    Additionally, install the following gems :

    • @@ -648,7 +648,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -

      Creating projectem (185.3ms)
    +
    Creating project (185.3ms)

    Please refer to API docs for optional options to benchmark()

    2.2. Controller

    Similarly, you could use this helper method inside controllers

    @@ -684,7 +684,7 @@ http://www.gnu.org/software/src-highlite -->

    3. Request Logging

    -

    Rails log files containt very useful information about the time taken to serve each request. Here’s a typical log file entry:

    +

    Rails log files contain very useful information about the time taken to serve each request. Here’s a typical log file entry:

    +
    [lifo@null mysql]$ gcruby extconf.rb --with-mysql-config
    +[lifo@null mysql]$ make && make install

    And you’re ready to go. Don’t forget to use gcruby and gcrake aliases when running the performance tests.

    -

    2. Helper methods

    +

    2. Command Line Tools

    +
    +

    Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools for allowing such quick and dirty performance testing:

    +

    2.1. benchmarker

    +

    benchmarker is a wrapper around Ruby’s Benchmark module.

    +

    Usage:

    +
    +
    +
    $ script/performance/benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ...
    +

    Examples:

    +
    +
    +
    $ script/performance/benchmarker 10 'Item.all' 'CouchItem.all'
    +

    If [times] argument is skipped, supplied methods are run just once:

    +
    +
    +
    $ script/performance/benchmarker 'Item.first' 'Item.last'
    +

    2.2. profiler

    +

    profiler is a wrapper around ruby-prof gem.

    +

    Usage:

    +
    +
    +
    $ script/performance/profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]
    +

    Examples:

    +
    +
    +
    $ script/performance/profiler 'Item.all'
    +

    This will profile Item.all with RubyProf::WALL_TIME measure mode. By default, flat output is printed to the shell.

    +
    +
    +
    $ script/performance/profiler 'Item.all' 10 graph
    +

    This will profile 10.times { Item.all } with RubyProf::WALL_TIME measure mode and print graph output to the shell.

    +

    If you want to store the output in a file:

    +
    +
    +
    $ script/performance/profiler 'Item.all' 10 graph 2> graph.txt
    +
    +

    3. Helper methods

    Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a given piece of code. The method is called benchmark() in all the three components.

    -

    2.1. Model

    +

    3.1. Model

    Creating project (185.3ms)

    Please refer to API docs for optional options to benchmark()

    -

    2.2. Controller

    +

    3.2. Controller

    Similarly, you could use this helper method inside controllers

    @@ -671,7 +741,7 @@ http://www.gnu.org/software/src-highlite --> Project.update_cached_projects endend -

    2.3. View

    +

    3.3. View

    And in views:

    <%= render :partial => @projects %> <% end %>
    -

    3. Request Logging

    +

    4. Request Logging

    Rails log files contain very useful information about the time taken to serve each request. Here’s a typical log file entry:

    @@ -704,9 +774,9 @@ http://www.gnu.org/software/src-highlite -->

    This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

    Michael Koziarski has an interesting blog post explaining the importance of using milliseconds as the metric.

    -

    4. Useful Profiling Tools

    +

    5. Useful Profiling Tools

    -

    4.1. Rails Plugins and Gems

    +

    5.1. Rails Plugins and Gems

    -

    4.2. External

    +

    5.2. External

    • @@ -743,7 +818,7 @@ http://www.gnu.org/software/src-highlite -->

    -

    5. Commercial Products

    +

    6. Commercial Products

    Rails has been lucky to have three startups dedicated to Rails specific performance tools:

      @@ -764,7 +839,7 @@ http://www.gnu.org/software/src-highlite -->
    -

    6. Changelog

    +

    7. Changelog

      diff --git a/railties/doc/guides/source/performance_testing.txt b/railties/doc/guides/source/performance_testing.txt index afa7f7545b..10c83e9eb2 100644 --- a/railties/doc/guides/source/performance_testing.txt +++ b/railties/doc/guides/source/performance_testing.txt @@ -363,6 +363,7 @@ Additionally, install the following gems : If installing +mysql+ fails, you can try to install it manually: +[source, shell] ---------------------------------------------------------------------------- [lifo@null mysql]$ gcruby extconf.rb --with-mysql-config [lifo@null mysql]$ make && make install @@ -370,6 +371,69 @@ If installing +mysql+ fails, you can try to install it manually: And you're ready to go. Don't forget to use +gcruby+ and +gcrake+ aliases when running the performance tests. +== Command Line Tools == + +Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools for allowing such quick and dirty performance testing: + +=== benchmarker === + ++benchmarker+ is a wrapper around Ruby's http://ruby-doc.org/core/classes/Benchmark.html[Benchmark] module. + +Usage: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ... +---------------------------------------------------------------------------- + +Examples: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/benchmarker 10 'Item.all' 'CouchItem.all' +---------------------------------------------------------------------------- + +If +[times]+ argument is skipped, supplied methods are run just once: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/benchmarker 'Item.first' 'Item.last' +---------------------------------------------------------------------------- + +=== profiler === + ++profiler+ is a wrapper around http://ruby-prof.rubyforge.org/[ruby-prof] gem. + +Usage: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html] +---------------------------------------------------------------------------- + +Examples: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/profiler 'Item.all' +---------------------------------------------------------------------------- + +This will profile +Item.all+ with +RubyProf::WALL_TIME+ measure mode. By default, flat output is printed to the shell. + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/profiler 'Item.all' 10 graph +---------------------------------------------------------------------------- + +This will profile +10.times { Item.all }+ with +RubyProf::WALL_TIME+ measure mode and print graph output to the shell. + +If you want to store the output in a file: + +[source, shell] +---------------------------------------------------------------------------- +$ script/performance/profiler 'Item.all' 10 graph 2> graph.txt +---------------------------------------------------------------------------- + == Helper methods == Rails provides various helper methods inside Active Record, Action Controller and Action View to measure the time taken by a given piece of code. The method is called +benchmark()+ in all the three components. @@ -451,6 +515,7 @@ Michael Koziarski has an http://www.therailsway.com/2009/1/6/requests-per-second * http://rails-analyzer.rubyforge.org/[Rails Analyzer] * http://www.flyingmachinestudios.com/projects/[Palmist] * http://github.com/josevalim/rails-footnotes/tree/master[Rails Footnotes] +* http://github.com/dsboulder/query_reviewer/tree/master[Query Reviewer] === External === -- cgit v1.2.3 From 1ea5c489f392183c2b58da0f49bf9f5f2c504ad7 Mon Sep 17 00:00:00 2001 From: Mike Gunderloy Date: Sat, 10 Jan 2009 10:49:33 -0600 Subject: Copy editing on performance test guide. --- railties/doc/guides/source/performance_testing.txt | 70 +++++++++++----------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/source/performance_testing.txt b/railties/doc/guides/source/performance_testing.txt index 10c83e9eb2..84a42cecde 100644 --- a/railties/doc/guides/source/performance_testing.txt +++ b/railties/doc/guides/source/performance_testing.txt @@ -4,16 +4,16 @@ Performance Testing Rails Applications This guide covers the various ways of performance testing a Ruby on Rails application. By referring to this guide, you will be able to: * Understand the various types of benchmarking and profiling metrics -* Generate performance/benchmarking tests -* Use GC patched Ruby binary to measure memory usage and object allocation -* Understand the information provided by Rails inside the log files +* Generate performance and benchmarking tests +* Use a GC-patched Ruby binary to measure memory usage and object allocation +* Understand the benchmarking information provided by Rails inside the log files * Learn about various tools facilitating benchmarking and profiling -Performance testing is an integral part of the development cycle. It is very important that you don't make your end users wait for too long before the page is completely loaded. Ensuring a pleasant browsing experience to the end users and cutting cost of unnecessary hardwares is important for any web application. +Performance testing is an integral part of the development cycle. It is very important that you don't make your end users wait for too long before the page is completely loaded. Ensuring a pleasant browsing experience for end users and cutting the cost of unnecessary hardware is important for any non-trivial web application. == Performance Test Cases == -Rails performance tests are integration tests designed for benchmarking and profiling the test code. With performance tests, you can determine where your application's memory or speed problems are coming from, and get a more in-depth picture of those problems. +Rails performance tests are a special type of integration tests, designed for benchmarking and profiling the test code. With performance tests, you can determine where your application's memory or speed problems are coming from, and get a more in-depth picture of those problems. In a freshly generated Rails application, +test/performance/browsing_test.rb+ contains an example of a performance test: @@ -30,7 +30,7 @@ class BrowsingTest < ActionController::PerformanceTest end ---------------------------------------------------------------------------- -The above example is a simple performance test case for profiling a GET request to the application's homepage. +This example is a simple performance test case for profiling a GET request to the application's homepage. === Generating performance tests === @@ -41,7 +41,7 @@ Rails provides a generator called +performance_test+ for creating new performanc script/generate performance_test homepage ---------------------------------------------------------------------------- -This generates +homepage_test.rb+ inside +test/performance+ directory: +This generates +homepage_test.rb+ in the +test/performance+ directory: [source, ruby] ---------------------------------------------------------------------------- @@ -100,7 +100,7 @@ end ==== Controller Example ==== -Performance tests are a special kind of integration tests. This allows you to use +get+ and +post+ methods inside the performance tests. +Because performance tests are a special kind of integration test, you can use the +get+ and +post+ methods in them. Here's the performance test for +HomeController#dashboard+ and +PostsController#create+: @@ -111,7 +111,7 @@ require 'performance_test_help' class PostPerformanceTest < ActionController::PerformanceTest def setup - # Application requires logged in user + # Application requires logged-in user login_as(:lifo) end @@ -125,11 +125,11 @@ class PostPerformanceTest < ActionController::PerformanceTest end ---------------------------------------------------------------------------- -You can find more details about +get+ and +post+ methods in API documentation of integration testing. +You can find more details about the +get+ and +post+ methods in the link:../testing_rails_applications.html#mgunderloy[Testing Rails Applications] guide. ==== Model Example ==== -Even though the performance tests are integration tests and hence closer to request/response cycle by nature, it doesn't prevent us from performance testing pure model code. +Even though the performance tests are integration tests and hence closer to the request/response cycle by nature, you can still performance test pure model code. Performance test for +Post+ model: @@ -156,7 +156,7 @@ Performance tests can be run in two modes : Benchmarking and Profiling. ==== Benchmarking ==== -Benchmarking helps find out how fast is a performance test. Each test case is run +4 times+ in benchmarking mode. +Benchmarking helps find out how fast each performance test runs. Each test case is run +4 times+ in benchmarking mode. To run performance tests in benchmarking mode: @@ -167,7 +167,7 @@ $ rake test:benchmark ==== Profiling ==== -Profiling helps you introspect into a performance test and provide an in-depth picture of the slow and memory hungry parts. Each Test case is run +1 time+ in profiling mode. +Profiling helps you see the details of a performance test and provide an in-depth picture of the slow and memory hungry parts. Each test case is run +1 time+ in profiling mode. To run performance tests in profiling mode: @@ -182,43 +182,43 @@ Benchmarking and profiling run performance tests in various modes described belo ==== Wall Time ==== -Measures the real world time elapsed during the test run. It is affected by any other processes concurrently running on the system. +Wall time measures the real world time elapsed during the test run. It is affected by any other processes concurrently running on the system. Mode : Benchmarking ==== Process Time ==== -Measures the time taken by the process. It is unaffected by any other processes running concurrently on the same system. Hence, process time is likely to be constant for any given performance test, irrespective of the machine load. +Process time measures the time taken by the process. It is unaffected by any other processes running concurrently on the same system. Hence, process time is likely to be constant for any given performance test, irrespective of the machine load. Mode : Profiling ==== Memory ==== -Measures the amount of memory used for the performance test case. +Memory measures the amount of memory used for the performance test case. -Mode : Benchmarking, Profiling [xref:gc[Requires GC Patched Ruby]] +Mode : Benchmarking, Profiling [xref:gc[Requires GC-Patched Ruby]] ==== Objects ==== -Measures the number of objects allocated for the performance test case. +Objects measures the number of objects allocated for the performance test case. -Mode : Benchmarking, Profiling [xref:gc[Requires GC Patched Ruby]] +Mode : Benchmarking, Profiling [xref:gc[Requires GC-Patched Ruby]] ==== GC Runs ==== -Measures the number of times GC was invoked for the performance test case. +GC Runs measures the number of times GC was invoked for the performance test case. -Mode : Benchmarking [xref:gc[Requires GC Patched Ruby]] +Mode : Benchmarking [xref:gc[Requires GC-Patched Ruby]] ==== GC Time ==== -Measures the amount of time spent in GC for the performance test case. +GC Time measures the amount of time spent in GC for the performance test case. -Mode : Benchmarking [xref:gc[Requires GC Patched Ruby]] +Mode : Benchmarking [xref:gc[Requires GC-Patched Ruby]] === Understanding the output === -Performance tests generate different outputs inside +tmp/performance+ directory based on the mode it is run in and the metric. +Performance tests generate different outputs inside +tmp/performance+ directory depending on their mode and metric. ==== Benchmarking ==== @@ -248,7 +248,7 @@ Performance test results are also appended to +.csv+ files inside +tmp/performan - BrowsingTest#test_homepage_objects.csv - BrowsingTest#test_homepage_wall_time.csv -As the results are appended to these files each time the performance tests are run in benchmarking mode, it enables you to collect data over a period of time which can be very helpful with various performance analysis. +As the results are appended to these files each time the performance tests are run in benchmarking mode, you can collect data over a period of time. This can be very helpful in analyzing the effects of code changes. Sample output of +BrowsingTest#test_homepage_wall_time.csv+: @@ -269,6 +269,8 @@ measurement,created_at,app,rails,ruby,platform ==== Profiling ==== +In profiling mode, you can choose from four types of output. + ===== Command line ===== This is a very basic form of output in profiling mode: @@ -297,14 +299,14 @@ Tree output is profiling information in calltree format for use by http://kcache By default, each performance test is run +4 times+ in benchmarking mode and +1 time+ in profiling. However, test runs can easily be configured. -CAUTION: That's a lie. But not for long. +CAUTION: Performance test configurability is not yet enabled in Rails. But it will be soon. [[gc]] -=== Installing GC Patched Ruby === +=== Installing GC-Patched Ruby === To get the best from Rails performance tests, you need to build a special Ruby binary with some super powers - http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch[GC patch] for measuring GC Runs/Time and memory/object allocation. -The process is fairly straight forward. If you've never compiled a Ruby binary before, follow the following steps to build a ruby binary inside your home directory: +The process is fairly straight forward. If you've never compiled a Ruby binary before, follow these steps to build a ruby binary inside your home directory: ==== Installation ==== @@ -373,7 +375,7 @@ And you're ready to go. Don't forget to use +gcruby+ and +gcrake+ aliases when r == Command Line Tools == -Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools for allowing such quick and dirty performance testing: +Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools that enable quick and dirty performance testing: === benchmarker === @@ -393,7 +395,7 @@ Examples: $ script/performance/benchmarker 10 'Item.all' 'CouchItem.all' ---------------------------------------------------------------------------- -If +[times]+ argument is skipped, supplied methods are run just once: +If the +[times]+ argument is omitted, supplied methods are run just once: [source, shell] ---------------------------------------------------------------------------- @@ -418,7 +420,7 @@ Examples: $ script/performance/profiler 'Item.all' ---------------------------------------------------------------------------- -This will profile +Item.all+ with +RubyProf::WALL_TIME+ measure mode. By default, flat output is printed to the shell. +This will profile +Item.all+ in +RubyProf::WALL_TIME+ measure mode. By default, it prints flat output to the shell. [source, shell] ---------------------------------------------------------------------------- @@ -449,14 +451,14 @@ Project.benchmark("Creating project") do end ---------------------------------------------------------------------------- -This benchmarks the code enclosed in +Project.benchmark("Creating project") do..end+ block and prints the result to the log file: +This benchmarks the code enclosed in the +Project.benchmark("Creating project") do..end+ block and prints the result to the log file: [source, ruby] ---------------------------------------------------------------------------- Creating project (185.3ms) ---------------------------------------------------------------------------- -Please refer to http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001336[API docs] for optional options to +benchmark()+ +Please refer to the http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001336[API docs] for additional options to +benchmark()+ === Controller === @@ -504,7 +506,7 @@ For this section, we're only interested in the last line: Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items] ---------------------------------------------------------------------------- -This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. +This data is fairly straightforward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It's safe to assume that the remaining 3 ms were spent inside the controller. Michael Koziarski has an http://www.therailsway.com/2009/1/6/requests-per-second[interesting blog post] explaining the importance of using milliseconds as the metric. -- cgit v1.2.3 From a5981517e6676818c3031834627e4a0763ce4fba Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 10 Jan 2009 16:55:42 +0000 Subject: Regen html --- railties/doc/guides/html/performance_testing.html | 71 ++++++++++++----------- 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/performance_testing.html b/railties/doc/guides/html/performance_testing.html index 563485ab79..2e6ba0a891 100644 --- a/railties/doc/guides/html/performance_testing.html +++ b/railties/doc/guides/html/performance_testing.html @@ -214,7 +214,7 @@ ul#navMain {
    • Tuning Test Runs
    • -
    • Installing GC Patched Ruby
    • +
    • Installing GC-Patched Ruby
    @@ -275,17 +275,17 @@ Understand the various types of benchmarking and profiling metrics
  • -Generate performance/benchmarking tests +Generate performance and benchmarking tests

  • -Use GC patched Ruby binary to measure memory usage and object allocation +Use a GC-patched Ruby binary to measure memory usage and object allocation

  • -Understand the information provided by Rails inside the log files +Understand the benchmarking information provided by Rails inside the log files

  • @@ -294,12 +294,12 @@ Learn about various tools facilitating benchmarking and profiling

  • -

    Performance testing is an integral part of the development cycle. It is very important that you don’t make your end users wait for too long before the page is completely loaded. Ensuring a pleasant browsing experience to the end users and cutting cost of unnecessary hardwares is important for any web application.

    +

    Performance testing is an integral part of the development cycle. It is very important that you don’t make your end users wait for too long before the page is completely loaded. Ensuring a pleasant browsing experience for end users and cutting the cost of unnecessary hardware is important for any non-trivial web application.

    1. Performance Test Cases

    -

    Rails performance tests are integration tests designed for benchmarking and profiling the test code. With performance tests, you can determine where your application’s memory or speed problems are coming from, and get a more in-depth picture of those problems.

    +

    Rails performance tests are a special type of integration tests, designed for benchmarking and profiling the test code. With performance tests, you can determine where your application’s memory or speed problems are coming from, and get a more in-depth picture of those problems.

    In a freshly generated Rails application, test/performance/browsing_test.rb contains an example of a performance test:

    get '/' end end
    -

    The above example is a simple performance test case for profiling a GET request to the application’s homepage.

    +

    This example is a simple performance test case for profiling a GET request to the application’s homepage.

    1.1. Generating performance tests

    Rails provides a generator called performance_test for creating new performance tests:

    @@ -324,7 +324,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
    script/generate performance_test homepage
    -

    This generates homepage_test.rb inside test/performance directory:

    +

    This generates homepage_test.rb in the test/performance directory:

    class PostPerformanceTest < ActionController::PerformanceTest def setup - # Application requires logged in user + # Application requires logged-in user login_as(:lifo) end @@ -405,9 +405,9 @@ http://www.gnu.org/software/src-highlite --> post '/posts', :post => { :body => 'lifo is fooling you' } end end
    -

    You can find more details about get and post methods in API documentation of integration testing.

    +

    You can find more details about the get and post methods in the Testing Rails Applications guide.

    1.2.2. Model Example

    -

    Even though the performance tests are integration tests and hence closer to request/response cycle by nature, it doesn’t prevent us from performance testing pure model code.

    +

    Even though the performance tests are integration tests and hence closer to the request/response cycle by nature, you can still performance test pure model code.

    Performance test for Post model:

    1.3. Modes

    Performance tests can be run in two modes : Benchmarking and Profiling.

    1.3.1. Benchmarking

    -

    Benchmarking helps find out how fast is a performance test. Each test case is run 4 times in benchmarking mode.

    +

    Benchmarking helps find out how fast each performance test runs. Each test case is run 4 times in benchmarking mode.

    To run performance tests in benchmarking mode:

    $ rake test:benchmark

    1.3.2. Profiling

    -

    Profiling helps you introspect into a performance test and provide an in-depth picture of the slow and memory hungry parts. Each Test case is run 1 time in profiling mode.

    +

    Profiling helps you see the details of a performance test and provide an in-depth picture of the slow and memory hungry parts. Each test case is run 1 time in profiling mode.

    To run performance tests in profiling mode:

    1.4. Metrics

    Benchmarking and profiling run performance tests in various modes described below.

    1.4.1. Wall Time

    -

    Measures the real world time elapsed during the test run. It is affected by any other processes concurrently running on the system.

    +

    Wall time measures the real world time elapsed during the test run. It is affected by any other processes concurrently running on the system.

    Mode : Benchmarking

    1.4.2. Process Time

    -

    Measures the time taken by the process. It is unaffected by any other processes running concurrently on the same system. Hence, process time is likely to be constant for any given performance test, irrespective of the machine load.

    +

    Process time measures the time taken by the process. It is unaffected by any other processes running concurrently on the same system. Hence, process time is likely to be constant for any given performance test, irrespective of the machine load.

    Mode : Profiling

    1.4.3. Memory

    -

    Measures the amount of memory used for the performance test case.

    -

    Mode : Benchmarking, Profiling [Requires GC Patched Ruby]

    +

    Memory measures the amount of memory used for the performance test case.

    +

    Mode : Benchmarking, Profiling [Requires GC-Patched Ruby]

    1.4.4. Objects

    -

    Measures the number of objects allocated for the performance test case.

    -

    Mode : Benchmarking, Profiling [Requires GC Patched Ruby]

    +

    Objects measures the number of objects allocated for the performance test case.

    +

    Mode : Benchmarking, Profiling [Requires GC-Patched Ruby]

    1.4.5. GC Runs

    -

    Measures the number of times GC was invoked for the performance test case.

    -

    Mode : Benchmarking [Requires GC Patched Ruby]

    +

    GC Runs measures the number of times GC was invoked for the performance test case.

    +

    Mode : Benchmarking [Requires GC-Patched Ruby]

    1.4.6. GC Time

    -

    Measures the amount of time spent in GC for the performance test case.

    -

    Mode : Benchmarking [Requires GC Patched Ruby]

    +

    GC Time measures the amount of time spent in GC for the performance test case.

    +

    Mode : Benchmarking [Requires GC-Patched Ruby]

    1.5. Understanding the output

    -

    Performance tests generate different outputs inside tmp/performance directory based on the mode it is run in and the metric.

    +

    Performance tests generate different outputs inside tmp/performance directory depending on their mode and metric.

    1.5.1. Benchmarking

    In benchmarking mode, performance tests generate two types of outputs :

    Command line
    @@ -513,7 +513,7 @@ BrowsingTest#test_homepage_wall_time.csv

    -

    As the results are appended to these files each time the performance tests are run in benchmarking mode, it enables you to collect data over a period of time which can be very helpful with various performance analysis.

    +

    As the results are appended to these files each time the performance tests are run in benchmarking mode, you can collect data over a period of time. This can be very helpful in analyzing the effects of code changes.

    Sample output of BrowsingTest#test_homepage_wall_time.csv:

    0.00603150000000008,2009-01-09T03:54:57Z,,2.3.0.master.859e150,ruby-1.8.6.111,i686-darwin9.1.0 0.00771250000000012,2009-01-09T15:46:03Z,,2.3.0.master.859e150,ruby-1.8.6.110,i686-darwin9.0.0

    1.5.2. Profiling

    +

    In profiling mode, you can choose from four types of output.

    Command line

    This is a very basic form of output in profiling mode:

    @@ -556,12 +557,12 @@ http://www.gnu.org/software/src-highlite -->
    - +
    Caution That’s a lie. But not for long.Performance test configurability is not yet enabled in Rails. But it will be soon.
    -

    1.7. Installing GC Patched Ruby

    +

    1.7. Installing GC-Patched Ruby

    To get the best from Rails performance tests, you need to build a special Ruby binary with some super powers - GC patch for measuring GC Runs/Time and memory/object allocation.

    -

    The process is fairly straight forward. If you’ve never compiled a Ruby binary before, follow the following steps to build a ruby binary inside your home directory:

    +

    The process is fairly straight forward. If you’ve never compiled a Ruby binary before, follow these steps to build a ruby binary inside your home directory:

    1.7.1. Installation

    Compile Ruby and apply this GC Patch:

    1.7.2. Download and Extract

    @@ -642,7 +643,7 @@ http://www.gnu.org/software/src-highlite -->

    2. Command Line Tools

    -

    Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools for allowing such quick and dirty performance testing:

    +

    Writing performance test cases could be an overkill when you are looking for one time tests. Rails ships with two command line tools that enable quick and dirty performance testing:

    2.1. benchmarker

    benchmarker is a wrapper around Ruby’s Benchmark module.

    Usage:

    @@ -659,7 +660,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
    $ script/performance/benchmarker 10 'Item.all' 'CouchItem.all'
    -

    If [times] argument is skipped, supplied methods are run just once:

    +

    If the [times] argument is omitted, supplied methods are run just once:

    $ script/performance/profiler 'Item.all'
    -

    This will profile Item.all with RubyProf::WALL_TIME measure mode. By default, flat output is printed to the shell.

    +

    This will profile Item.all in RubyProf::WALL_TIME measure mode. By default, it prints flat output to the shell.

    project.create_manager("name" => "David") project.milestones << Milestone.find(:all) end
    -

    This benchmarks the code enclosed in Project.benchmark("Creating project") do..end block and prints the result to the log file:

    +

    This benchmarks the code enclosed in the Project.benchmark("Creating project") do..end block and prints the result to the log file:

    Creating project (185.3ms)
    -

    Please refer to API docs for optional options to benchmark()

    +

    Please refer to the API docs for additional options to benchmark()

    3.2. Controller

    Similarly, you could use this helper method inside controllers

    @@ -771,7 +772,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
    Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]
    -

    This data is fairly straight forward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

    +

    This data is fairly straightforward to understand. Rails uses millisecond(ms) as the metric to measures the time taken. The complete request spent 5 ms inside Rails, out of which 2 ms were spent rendering views and none was spent communication with the database. It’s safe to assume that the remaining 3 ms were spent inside the controller.

    Michael Koziarski has an interesting blog post explaining the importance of using milliseconds as the metric.

    5. Useful Profiling Tools

    -- cgit v1.2.3 From 32c3ce1d2bf50b42481b4cc8d20d90b495bd200d Mon Sep 17 00:00:00 2001 From: CassioMarques Date: Sat, 10 Jan 2009 17:38:41 -0200 Subject: Adding text about conditional callbacks --- .../html/activerecord_validations_callbacks.html | 86 ++++++++++++++++++---- .../source/activerecord_validations_callbacks.txt | 52 ++++++++++++- 2 files changed, 124 insertions(+), 14 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/activerecord_validations_callbacks.html b/railties/doc/guides/html/activerecord_validations_callbacks.html index 7936de209d..bdd5e723ea 100644 --- a/railties/doc/guides/html/activerecord_validations_callbacks.html +++ b/railties/doc/guides/html/activerecord_validations_callbacks.html @@ -292,6 +292,20 @@ ul#navMain {
  • + Conditional callbacks + +
  • +
  • Available callbacks
      @@ -735,7 +749,7 @@ http://www.gnu.org/software/src-highlite -->

      Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the :if and :unless options, which can take a symbol, a string or a Ruby Proc. You may use the :if option when you want to specify when the validation should happen. If you want to specify when the validation should not happen, then you may use the :unless option.

      5.1. Using a symbol with the :if and :unless options

      -

      You can associated the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.

      +

      You can associate the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.

      +
      class Order < ActiveRecord::Base
      +  before_save :normalize_card_number, :if => :paid_with_card?
      +end
      +

      10.2. Using a string with the :if and :unless options

      +

      You can also use a string that will be evaluated using :eval and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.

      +
      +
      +
      class Order < ActiveRecord::Base
      +  before_save :normalize_card_number, :if => "paid_with_card?"
      +end
      +

      10.3. Using a Proc object with the :if and :unless options

      +

      Finally, it’s possible to associate :if and :unless with a Ruby Proc object. This option is best suited when writing short validation methods, usually one-liners.

      +
      +
      +
      class Order < ActiveRecord::Base
      +  before_save :normalize_card_number,
      +    :if => Proc.new { |order| order.paid_with_card? }
      +end
      +

      10.4. Multiple Conditions for Callbacks

      +

      When writing conditional callbacks, it’s possible to mix both :if and :unless in the same callback declaration.

      +
      +
      +
      class Comment < ActiveRecord::Base
      +  after_create :send_email_to_author, :if => :author_wants_emails?,
      +    :unless => Proc.new { |comment| comment.post.ignore_comments? }
      +end
      +
      +

      11. Available callbacks

      Here is a list with all the available Active Record callbacks, listed in the same order in which they will get called during the respective operations.

      -

      10.1. Callbacks called both when creating or updating a record.

      +

      11.1. Callbacks called both when creating or updating a record.

      • @@ -1156,7 +1216,7 @@ Readability, since your callback declarations will live at the beggining of your

      -

      10.2. Callbacks called only when creating a new record.

      +

      11.2. Callbacks called only when creating a new record.

      • @@ -1184,7 +1244,7 @@ Readability, since your callback declarations will live at the beggining of your

      -

      10.3. Callbacks called only when updating an existing record.

      +

      11.3. Callbacks called only when updating an existing record.

      • @@ -1212,7 +1272,7 @@ Readability, since your callback declarations will live at the beggining of your

      -

      10.4. Callbacks called when removing a record from the database.

      +

      11.4. Callbacks called when removing a record from the database.

      • @@ -1231,16 +1291,16 @@ Readability, since your callback declarations will live at the beggining of your

      The before_destroy and after_destroy callbacks will only be called if you delete the model using either the destroy instance method or one of the destroy or destroy_all class methods of your Active Record class. If you use delete or delete_all no callback operations will run, since Active Record will not instantiate any objects, accessing the records to be deleted directly in the database.

      -

      10.5. The after_initialize and after_find callbacks

      +

      11.5. The after_initialize and after_find callbacks

      The after_initialize callback will be called whenever an Active Record object is instantiated, either by direcly using new or when a record is loaded from the database. It can be useful to avoid the need to directly override your Active Record initialize method.

      The after_find callback will be called whenever Active Record loads a record from the database. When used together with after_initialize it will run first, since Active Record will first read the record from the database and them create the model object that will hold it.

      The after_initialize and after_find callbacks are a bit different from the others, since the only way to register those callbacks is by defining them as methods. If you try to register after_initialize or after_find using macro-style class methods, they will just be ignored. This behaviour is due to performance reasons, since after_initialize and after_find will both be called for each record found in the database, significantly slowing down the queries.

      -

      11. Halting Execution

      +

      12. Halting Execution

      As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model’s validations, the registered callbacks and the database operation to be executed. However, if at any moment one of the before_create, before_save, before_update or before_destroy callback methods returns a boolean false (not nil) value, this execution chain will be halted and the desired operation will not complete: your model will not get persisted in the database, or your records will not get deleted and so on.

      -

      12. Callback classes

      +

      13. Callback classes

      Sometimes the callback methods that you’ll write will be useful enough to be reused at other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them.

      Here’s an example where we create a class with a after_destroy callback for a PictureFile model.

      @@ -1285,7 +1345,7 @@ http://www.gnu.org/software/src-highlite --> end

      You can declare as many callbacks as you want inside your callback classes.

      -

      13. Observers

      +

      14. Observers

      Active Record callbacks are a powerful feature, but they can pollute your model implementation with code that’s not directly related to the model’s purpose. In object-oriented software, it’s always a good idea to design your classes with a single responsibility in the whole system. For example, it wouldn’t make much sense to have a User model with a method that writes data about a login attempt to a log file. Whenever you’re using callbacks to write code that’s not directly related to your model class purposes, it may be a good moment to create an Observer.

      An Active Record Observer is an object that links itself to a model and registers its methods for callbacks. Your model’s implementation remains clean, while you can reuse the code in the Observer to add behaviour to more than one model class. OK, you may say that we can also do that using callback classes, but it would still force us to add code to our model’s implementation.

      @@ -1311,7 +1371,7 @@ http://www.gnu.org/software/src-highlite -->
      class Auditor < ActiveRecord::Observer
         observe User, Registration, Invoice
       end
      -

      13.1. Registering observers

      +

      14.1. Registering observers

      If you paid attention, you may be wondering where Active Record Observers are referenced in our applications, so they get instantiated and begin to interact with our models. For observers to work we need to register them somewhere. The usual place to do that is in our application’s config/environment.rb file. In this file there is a commented-out line where we can define the observers that our application should load at start-up.

      config.active_record.observers = :registration_observer, :auditor

      You can uncomment the line with config.active_record.observers and change the symbols for the name of the observers that should be registered.

      It’s also possible to register callbacks in any of the files living at config/environments/, if you want an observer to work only in a specific environment. There is not a config.active_record.observers line at any of those files, but you can simply add it.

      -

      13.2. Where to put the observers' source files

      +

      14.2. Where to put the observers' source files

      By convention, you should always save your observers' source files inside app/models.

      -

      14. Changelog

      +

      15. Changelog

      diff --git a/railties/doc/guides/source/activerecord_validations_callbacks.txt b/railties/doc/guides/source/activerecord_validations_callbacks.txt index 7d37df1ed2..09cc1fdb20 100644 --- a/railties/doc/guides/source/activerecord_validations_callbacks.txt +++ b/railties/doc/guides/source/activerecord_validations_callbacks.txt @@ -359,7 +359,7 @@ Sometimes it will make sense to validate an object just when a given predicate i === Using a symbol with the +:if+ and +:unless+ options -You can associated the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option. +You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option. [source, ruby] ------------------------------------------------------------------ @@ -678,6 +678,56 @@ In Rails, the preferred way of registering callbacks is by using macro-style cla CAUTION: Remember to always declare the callback methods as being protected or private. These methods should never be public, otherwise it will be possible to call them from code outside the model, violating object encapsulation and exposing implementation details. +== Conditional callbacks + +Like in validations, we can also make our callbacks conditional, calling then only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a Ruby Proc. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option. + +=== Using a symbol with the +:if+ and +:unless+ options + +You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. If this method returns +false+ the callback won't be executed. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check the if the callback should be executed. + +[source, ruby] +------------------------------------------------------------------ +class Order < ActiveRecord::Base + before_save :normalize_card_number, :if => :paid_with_card? +end +------------------------------------------------------------------ + +=== Using a string with the +:if+ and +:unless+ options + +You can also use a string that will be evaluated using +:eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition. + +[source, ruby] +------------------------------------------------------------------ +class Order < ActiveRecord::Base + before_save :normalize_card_number, :if => "paid_with_card?" +end +------------------------------------------------------------------ + +=== Using a Proc object with the +:if+ and :+unless+ options + +Finally, it's possible to associate +:if+ and +:unless+ with a Ruby Proc object. This option is best suited when writing short validation methods, usually one-liners. + +[source, ruby] +------------------------------------------------------------------ +class Order < ActiveRecord::Base + before_save :normalize_card_number, + :if => Proc.new { |order| order.paid_with_card? } +end +------------------------------------------------------------------ + +=== Multiple Conditions for Callbacks + +When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration. + +[source, ruby] +------------------------------------------------------------------ +class Comment < ActiveRecord::Base + after_create :send_email_to_author, :if => :author_wants_emails?, + :unless => Proc.new { |comment| comment.post.ignore_comments? } +end +------------------------------------------------------------------ + == Available callbacks Here is a list with all the available Active Record callbacks, listed in the same order in which they will get called during the respective operations. -- cgit v1.2.3 From cf4b24407ada79c133fbae1ec7db692882225956 Mon Sep 17 00:00:00 2001 From: CassioMarques Date: Sat, 10 Jan 2009 17:49:12 -0200 Subject: Getting rid of the example of callback registration by overrinding the callback method name --- .../html/activerecord_validations_callbacks.html | 40 ++-------------------- .../source/activerecord_validations_callbacks.txt | 29 +--------------- 2 files changed, 3 insertions(+), 66 deletions(-) (limited to 'railties/doc/guides') diff --git a/railties/doc/guides/html/activerecord_validations_callbacks.html b/railties/doc/guides/html/activerecord_validations_callbacks.html index bdd5e723ea..0862776f53 100644 --- a/railties/doc/guides/html/activerecord_validations_callbacks.html +++ b/railties/doc/guides/html/activerecord_validations_callbacks.html @@ -285,10 +285,6 @@ ul#navMain {
    • Callbacks registration
    • -
    • Registering callbacks by overriding the callback methods
    • - -
    • Registering callbacks by using macro-style class methods
    • -
  • @@ -649,7 +645,7 @@ http://www.gnu.org/software/src-highlite -->
  • Note If you want to validate the presence of a boolean field (where the real values are true and false), you will want to use validates_inclusion_of :field_name, :in => [true, false] This is due to the way Object#blank? handles boolean values. false.blank? # => trueIf you want to validate the presence of a boolean field (where the real values are true and false), you will want to use validates_inclusion_of :field_name, :in ⇒ [true, false] This is due to the way Object#blank? handles boolean values. false.blank? # ⇒ true

    The default error message for validates_presence_of is "can’t be empty".

    @@ -1069,26 +1065,7 @@ An object of the ActionView::Helpers::InstanceTag class.

    Callbacks are methods that get called at certain moments of an object’s lifecycle. With callbacks it’s possible to write code that will run whenever an Active Record object is created, saved, updated, deleted or loaded from the database.

    9.1. Callbacks registration

    -

    In order to use the available callbacks, you need to registrate them. There are two ways of doing that.

    -

    9.2. Registering callbacks by overriding the callback methods

    -

    You can specify the callback method directly, by overriding it. Let’s see how it works using the before_validation callback, which will surprisingly run right before any validation is done.

    -
    -
    -
    class User < ActiveRecord::Base
    -  validates_presence_of :login, :email
    -
    -  protected
    -  def before_validation
    -    if self.login.nil?
    -      self.login = email unless email.blank?
    -    end
    -  end
    -end
    -

    9.3. Registering callbacks by using macro-style class methods

    -

    The other way you can register a callback method is by implementing it as an ordinary method, and then using a macro-style class method to register it as a callback. The last example could be written like that:

    +

    In order to use the available callbacks, you need to registrate them. You can do that by implementing them as an ordinary methods, and then using a macro-style class method to register then as callbacks.

    before_create {|user| user.name = user.login.capitalize if user.name.blank?} end
    -

    In Rails, the preferred way of registering callbacks is by using macro-style class methods. The main advantages of using macro-style class methods are:

    -
      -
    • -

      -You can add more than one method for each type of callback. Those methods will be queued for execution at the same order they were registered. -

      -
    • -
    • -

      -Readability, since your callback declarations will live at the beggining of your models' files. -

      -
    • -
    diff --git a/railties/doc/guides/source/activerecord_validations_callbacks.txt b/railties/doc/guides/source/activerecord_validations_callbacks.txt index 09cc1fdb20..29bff0c7b3 100644 --- a/railties/doc/guides/source/activerecord_validations_callbacks.txt +++ b/railties/doc/guides/source/activerecord_validations_callbacks.txt @@ -620,29 +620,7 @@ Callbacks are methods that get called at certain moments of an object's lifecycl === Callbacks registration -In order to use the available callbacks, you need to registrate them. There are two ways of doing that. - -=== Registering callbacks by overriding the callback methods - -You can specify the callback method directly, by overriding it. Let's see how it works using the +before_validation+ callback, which will surprisingly run right before any validation is done. - -[source, ruby] ------------------------------------------------------------------- -class User < ActiveRecord::Base - validates_presence_of :login, :email - - protected - def before_validation - if self.login.nil? - self.login = email unless email.blank? - end - end -end ------------------------------------------------------------------- - -=== Registering callbacks by using macro-style class methods - -The other way you can register a callback method is by implementing it as an ordinary method, and then using a macro-style class method to register it as a callback. The last example could be written like that: +In order to use the available callbacks, you need to registrate them. You can do that by implementing them as an ordinary methods, and then using a macro-style class method to register then as callbacks. [source, ruby] ------------------------------------------------------------------ @@ -671,11 +649,6 @@ class User < ActiveRecord::Base end ------------------------------------------------------------------ -In Rails, the preferred way of registering callbacks is by using macro-style class methods. The main advantages of using macro-style class methods are: - -* You can add more than one method for each type of callback. Those methods will be queued for execution at the same order they were registered. -* Readability, since your callback declarations will live at the beggining of your models' files. - CAUTION: Remember to always declare the callback methods as being protected or private. These methods should never be public, otherwise it will be possible to call them from code outside the model, violating object encapsulation and exposing implementation details. == Conditional callbacks -- cgit v1.2.3