Skip to content
This repository
Browse code

benchmarker and profiler now use the new performance testing tools (s…

…upport for Rubinius and JRuby and high configurability)
  • Loading branch information...
commit 810fb2b5273591ff396ae9bcc1cf78b5d575c33d 1 parent 9ca97a6
Gonçalo Silva authored May 10, 2011
11  activesupport/lib/active_support/testing/performance.rb
@@ -23,12 +23,15 @@ module Performance
23 23
       
24 24
       # each implementation should define metrics and freeze the defaults
25 25
       DEFAULTS =
26  
-        if ARGV.include?('--benchmark')  # HAX for rake test
  26
+        if ARGV.include?('--benchmark') # HAX for rake test
27 27
           { :runs => 4,
28  
-            :output => 'tmp/performance' }
  28
+            :output => 'tmp/performance',
  29
+            :benchmark => true }
29 30
         else
  31
+          puts "not"
30 32
           { :runs => 1,
31  
-            :output => 'tmp/performance' }
  33
+            :output => 'tmp/performance',
  34
+            :benchmark => false }
32 35
         end
33 36
       
34 37
       def full_profile_options
@@ -130,7 +133,7 @@ def run_warmup
130 133
         end
131 134
         
132 135
         def run_profile(metric)
133  
-          klass = ARGV.include?('--benchmark') ? Benchmarker : Profiler
  136
+          klass = full_profile_options[:benchmark] ? Benchmarker : Profiler
134 137
           performer = klass.new(self, metric)
135 138
 
136 139
           performer.run
50  railties/guides/source/performance_testing.textile
Source Rendered
@@ -458,55 +458,47 @@ Writing performance test cases could be an overkill when you are looking for one
458 458
 
459 459
 h4. +benchmarker+
460 460
 
461  
-+benchmarker+ is a wrapper around Ruby's "Benchmark":http://ruby-doc.org/core/classes/Benchmark.html standard library.
462  
-
463 461
 Usage:
464 462
 
465 463
 <shell>
466  
-$ rails benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ...
  464
+Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]
  465
+    -r, --runs N                     Number of runs.
  466
+                                     Default: 4
  467
+    -o, --output PATH                Directory to use when writing the results.
  468
+                                     Default: tmp/performance
  469
+    -m, --metrics a,b,c              Metrics to use.
  470
+                                     Default: wall_time,memory,objects,gc_runs,gc_time
467 471
 </shell>
468 472
 
469  
-Examples:
  473
+Example:
470 474
 
471 475
 <shell>
472  
-$ rails benchmarker 10 'Item.all' 'CouchItem.all'
473  
-</shell>
474  
-
475  
-If the +[times]+ argument is omitted, supplied methods are run just once:
476  
-
477  
-<shell>
478  
-$ rails benchmarker 'Item.first' 'Item.last'
  476
+$ rails benchmarker 'Item.all' 'CouchItem.all' --runs 3 --metrics wall_time,memory
479 477
 </shell>
480 478
 
481 479
 h4. +profiler+
482 480
 
483  
-+profiler+ is a wrapper around the "ruby-prof":http://ruby-prof.rubyforge.org gem.
484  
-
485 481
 Usage:
486 482
 
487 483
 <shell>
488  
-$ rails profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]
489  
-</shell>
490  
-
491  
-Examples:
492  
-
493  
-<shell>
494  
-$ rails profiler 'Item.all'
  484
+Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]
  485
+    -r, --runs N                     Number of runs.
  486
+                                     Default: 1
  487
+    -o, --output PATH                Directory to use when writing the results.
  488
+                                     Default: tmp/performance
  489
+        --metrics a,b,c              Metrics to use.
  490
+                                     Default: process_time,memory,objects
  491
+    -m, --formats x,y,z              Formats to output to.
  492
+                                     Default: flat,graph_html,call_tree
495 493
 </shell>
496 494
 
497  
-This will profile +Item.all+ in +RubyProf::WALL_TIME+ measure mode. By default, it prints flat output to the shell.
  495
+Example:
498 496
 
499 497
 <shell>
500  
-$ rails profiler 'Item.all' 10 graph
  498
+$ rails profiler 'Item.all' 'CouchItem.all' --runs 2 --metrics process_time --formats flat
501 499
 </shell>
502 500
 
503  
-This will profile +10.times { Item.all }+ with +RubyProf::WALL_TIME+ measure mode and print graph output to the shell.
504  
-
505  
-If you want to store the output in a file:
506  
-
507  
-<shell>
508  
-$ rails profiler 'Item.all' 10 graph 2> graph.txt
509  
-</shell>
  501
+NOTE: Metrics and formats vary from interpreter to interpreter. Pass +--help+ to each tool to see the defaults for your interpreter.
510 502
 
511 503
 h3. Helper Methods
512 504
 
47  railties/lib/rails/commands/benchmarker.rb
... ...
@@ -1,25 +1,34 @@
1  
-require 'active_support/core_ext/object/inclusion'
  1
+require 'optparse'
  2
+require 'rails/test_help'
  3
+require 'rails/performance_test_help'
2 4
 
3  
-if ARGV.first.in?([nil, "-h", "--help"])
4  
-  puts "Usage: rails benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ..."
5  
-  exit 1
6  
-end
  5
+ARGV.push('--benchmark') # HAX
  6
+require 'active_support/testing/performance'
  7
+ARGV.pop
7 8
 
8  
-begin
9  
-  N = Integer(ARGV.first)
10  
-  ARGV.shift
11  
-rescue ArgumentError
12  
-  N = 1
  9
+def options
  10
+  options = {}
  11
+  defaults = ActiveSupport::Testing::Performance::DEFAULTS
  12
+  
  13
+  OptionParser.new do |opt|
  14
+    opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]"
  15
+    opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r }
  16
+    opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o }
  17
+    opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) }
  18
+    opt.parse!(ARGV)
  19
+  end
  20
+  
  21
+  options
13 22
 end
14 23
 
15  
-require 'benchmark'
16  
-include Benchmark
17  
-
18  
-# Don't include compilation in the benchmark
19  
-ARGV.each { |expression| eval(expression) }
20  
-
21  
-bm(6) do |x|
22  
-  ARGV.each_with_index do |expression, idx|
23  
-    x.report("##{idx + 1}") { N.times { eval(expression) } }
  24
+class BenchmarkerTest < ActionDispatch::PerformanceTest
  25
+  self.profile_options = options
  26
+  
  27
+  ARGV.each do |expression|
  28
+    eval <<-RUBY
  29
+      def test_#{expression.parameterize('_')}
  30
+        #{expression}
  31
+      end
  32
+    RUBY
24 33
   end
25 34
 end
70  railties/lib/rails/commands/profiler.rb
... ...
@@ -1,48 +1,32 @@
1  
-require 'active_support/core_ext/object/inclusion'
  1
+require 'optparse'
  2
+require 'rails/test_help'
  3
+require 'rails/performance_test_help'
  4
+require 'active_support/testing/performance'
2 5
 
3  
-if ARGV.first.in?([nil, "-h", "--help"])
4  
-  $stderr.puts "Usage: rails profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]"
5  
-  exit(1)
6  
-end
7  
-
8  
-# Define a method to profile.
9  
-if ARGV[1] and ARGV[1].to_i > 1
10  
-  eval "def profile_me() #{ARGV[1]}.times { #{ARGV[0]} } end"
11  
-else
12  
-  eval "def profile_me() #{ARGV[0]} end"
  6
+def options
  7
+  options = {}
  8
+  defaults = ActiveSupport::Testing::Performance::DEFAULTS
  9
+  
  10
+  OptionParser.new do |opt|
  11
+    opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]"
  12
+    opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r }
  13
+    opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o }
  14
+    opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) }
  15
+    opt.on('-f', '--formats x,y,z', Array, 'Formats to output to.', "Default: #{defaults[:formats].join(",")}") { |m| options[:formats] = m.map(&:to_sym) }
  16
+    opt.parse!(ARGV)
  17
+  end
  18
+  
  19
+  options
13 20
 end
14 21
 
15  
-# Use the ruby-prof extension if available.  Fall back to stdlib profiler.
16  
-begin
17  
-  begin
18  
-    require "ruby-prof"
19  
-    $stderr.puts 'Using the ruby-prof extension.'
20  
-    RubyProf.measure_mode = RubyProf::WALL_TIME
21  
-    RubyProf.start
22  
-    profile_me
23  
-    results = RubyProf.stop
24  
-    if ARGV[2]
25  
-      printer_class = RubyProf.const_get((ARGV[2] + "_printer").classify)
26  
-    else
27  
-      printer_class = RubyProf::FlatPrinter
28  
-    end
29  
-    printer = printer_class.new(results)
30  
-    printer.print($stderr)
31  
-  rescue LoadError
32  
-    require "prof"
33  
-    $stderr.puts 'Using the old ruby-prof extension.'
34  
-    Prof.clock_mode = Prof::GETTIMEOFDAY
35  
-    Prof.start
36  
-    profile_me
37  
-    results = Prof.stop
38  
-    require 'rubyprof_ext'
39  
-    Prof.print_profile(results, $stderr)
  22
+class ProfilerTest < ActionDispatch::PerformanceTest
  23
+  self.profile_options = options
  24
+  
  25
+  ARGV.each do |expression|
  26
+    eval <<-RUBY
  27
+      def test_#{expression.parameterize('_')}
  28
+        #{expression}
  29
+      end
  30
+    RUBY
40 31
   end
41  
-rescue LoadError
42  
-  require 'profiler'
43  
-  $stderr.puts 'Using the standard Ruby profiler.'
44  
-  Profiler__.start_profile
45  
-  profile_me
46  
-  Profiler__.stop_profile
47  
-  Profiler__.print_profile($stderr)
48 32
 end

0 notes on commit 810fb2b

Please sign in to comment.
Something went wrong with that request. Please try again.