benchmarker and profiler now use the new performance testing tools (support for Rubinius and JRuby and high configurability)

This commit is contained in:
Gonçalo Silva 2011-05-10 02:33:01 +01:00
parent 9ca97a6baf
commit dcc99e23cd
4 changed files with 85 additions and 98 deletions

@ -23,12 +23,14 @@ module Performance
# each implementation should define metrics and freeze the defaults
DEFAULTS =
if ARGV.include?('--benchmark') # HAX for rake test
if ARGV.include?('--benchmark') # HAX for rake test
{ :runs => 4,
:output => 'tmp/performance' }
:output => 'tmp/performance',
:benchmark => true }
else
{ :runs => 1,
:output => 'tmp/performance' }
:output => 'tmp/performance',
:benchmark => false }
end
def full_profile_options
@ -130,7 +132,7 @@ def run_warmup
end
def run_profile(metric)
klass = ARGV.include?('--benchmark') ? Benchmarker : Profiler
klass = full_profile_options[:benchmark] ? Benchmarker : Profiler
performer = klass.new(self, metric)
performer.run

@ -458,55 +458,47 @@ Writing performance test cases could be an overkill when you are looking for one
h4. +benchmarker+
+benchmarker+ is a wrapper around Ruby's "Benchmark":http://ruby-doc.org/core/classes/Benchmark.html standard library.
Usage:
<shell>
$ rails benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ...
Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]
-r, --runs N Number of runs.
Default: 4
-o, --output PATH Directory to use when writing the results.
Default: tmp/performance
-m, --metrics a,b,c Metrics to use.
Default: wall_time,memory,objects,gc_runs,gc_time
</shell>
Examples:
Example:
<shell>
$ rails benchmarker 10 'Item.all' 'CouchItem.all'
</shell>
If the +[times]+ argument is omitted, supplied methods are run just once:
<shell>
$ rails benchmarker 'Item.first' 'Item.last'
$ rails benchmarker 'Item.all' 'CouchItem.all' --runs 3 --metrics wall_time,memory
</shell>
h4. +profiler+
+profiler+ is a wrapper around the "ruby-prof":http://ruby-prof.rubyforge.org gem.
Usage:
<shell>
$ rails profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]
Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]
-r, --runs N Number of runs.
Default: 1
-o, --output PATH Directory to use when writing the results.
Default: tmp/performance
--metrics a,b,c Metrics to use.
Default: process_time,memory,objects
-m, --formats x,y,z Formats to output to.
Default: flat,graph_html,call_tree
</shell>
Examples:
Example:
<shell>
$ rails profiler 'Item.all'
$ rails profiler 'Item.all' 'CouchItem.all' --runs 2 --metrics process_time --formats flat
</shell>
This will profile +Item.all+ in +RubyProf::WALL_TIME+ measure mode. By default, it prints flat output to the shell.
<shell>
$ rails profiler 'Item.all' 10 graph
</shell>
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:
<shell>
$ rails profiler 'Item.all' 10 graph 2> graph.txt
</shell>
NOTE: Metrics and formats vary from interpreter to interpreter. Pass +--help+ to each tool to see the defaults for your interpreter.
h3. Helper Methods

@ -1,25 +1,34 @@
require 'active_support/core_ext/object/inclusion'
require 'optparse'
require 'rails/test_help'
require 'rails/performance_test_help'
if ARGV.first.in?([nil, "-h", "--help"])
puts "Usage: rails benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ..."
exit 1
ARGV.push('--benchmark') # HAX
require 'active_support/testing/performance'
ARGV.pop
def options
options = {}
defaults = ActiveSupport::Testing::Performance::DEFAULTS
OptionParser.new do |opt|
opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]"
opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r }
opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o }
opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) }
opt.parse!(ARGV)
end
options
end
begin
N = Integer(ARGV.first)
ARGV.shift
rescue ArgumentError
N = 1
end
require 'benchmark'
include Benchmark
# Don't include compilation in the benchmark
ARGV.each { |expression| eval(expression) }
bm(6) do |x|
ARGV.each_with_index do |expression, idx|
x.report("##{idx + 1}") { N.times { eval(expression) } }
class BenchmarkerTest < ActionDispatch::PerformanceTest
self.profile_options = options
ARGV.each do |expression|
eval <<-RUBY
def test_#{expression.parameterize('_')}
#{expression}
end
RUBY
end
end

@ -1,48 +1,32 @@
require 'active_support/core_ext/object/inclusion'
require 'optparse'
require 'rails/test_help'
require 'rails/performance_test_help'
require 'active_support/testing/performance'
if ARGV.first.in?([nil, "-h", "--help"])
$stderr.puts "Usage: rails profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]"
exit(1)
end
# Define a method to profile.
if ARGV[1] and ARGV[1].to_i > 1
eval "def profile_me() #{ARGV[1]}.times { #{ARGV[0]} } end"
else
eval "def profile_me() #{ARGV[0]} end"
end
# Use the ruby-prof extension if available. Fall back to stdlib profiler.
begin
begin
require "ruby-prof"
$stderr.puts 'Using the ruby-prof extension.'
RubyProf.measure_mode = RubyProf::WALL_TIME
RubyProf.start
profile_me
results = RubyProf.stop
if ARGV[2]
printer_class = RubyProf.const_get((ARGV[2] + "_printer").classify)
else
printer_class = RubyProf::FlatPrinter
end
printer = printer_class.new(results)
printer.print($stderr)
rescue LoadError
require "prof"
$stderr.puts 'Using the old ruby-prof extension.'
Prof.clock_mode = Prof::GETTIMEOFDAY
Prof.start
profile_me
results = Prof.stop
require 'rubyprof_ext'
Prof.print_profile(results, $stderr)
def options
options = {}
defaults = ActiveSupport::Testing::Performance::DEFAULTS
OptionParser.new do |opt|
opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]"
opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r }
opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o }
opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) }
opt.on('-f', '--formats x,y,z', Array, 'Formats to output to.', "Default: #{defaults[:formats].join(",")}") { |m| options[:formats] = m.map(&:to_sym) }
opt.parse!(ARGV)
end
options
end
class ProfilerTest < ActionDispatch::PerformanceTest
self.profile_options = options
ARGV.each do |expression|
eval <<-RUBY
def test_#{expression.parameterize('_')}
#{expression}
end
RUBY
end
rescue LoadError
require 'profiler'
$stderr.puts 'Using the standard Ruby profiler.'
Profiler__.start_profile
profile_me
Profiler__.stop_profile
Profiler__.print_profile($stderr)
end