diff options
-rw-r--r-- | activesupport/lib/active_support/testing/performance.rb | 11 | ||||
-rw-r--r-- | railties/guides/source/performance_testing.textile | 50 | ||||
-rw-r--r-- | railties/lib/rails/commands/benchmarker.rb | 47 | ||||
-rw-r--r-- | railties/lib/rails/commands/profiler.rb | 70 |
4 files changed, 83 insertions, 95 deletions
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index b62d9b16e1..4e970c034f 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -23,12 +23,15 @@ module ActiveSupport # 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 + puts "not" { :runs => 1, - :output => 'tmp/performance' } + :output => 'tmp/performance', + :benchmark => false } end def full_profile_options @@ -130,7 +133,7 @@ module ActiveSupport 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 diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile index bbf200e66f..0f49bffdf7 100644 --- a/railties/guides/source/performance_testing.textile +++ b/railties/guides/source/performance_testing.textile @@ -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] -</shell> - -Examples: - -<shell> -$ rails profiler 'Item.all' +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> -This will profile +Item.all+ in +RubyProf::WALL_TIME+ measure mode. By default, it prints flat output to the shell. +Example: <shell> -$ rails profiler 'Item.all' 10 graph +$ rails profiler 'Item.all' 'CouchItem.all' --runs 2 --metrics process_time --formats flat </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 diff --git a/railties/lib/rails/commands/benchmarker.rb b/railties/lib/rails/commands/benchmarker.rb index f230f405c0..b06c915ac3 100644 --- a/railties/lib/rails/commands/benchmarker.rb +++ b/railties/lib/rails/commands/benchmarker.rb @@ -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 -end +ARGV.push('--benchmark') # HAX +require 'active_support/testing/performance' +ARGV.pop -begin - N = Integer(ARGV.first) - ARGV.shift -rescue ArgumentError - N = 1 +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 -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 diff --git a/railties/lib/rails/commands/profiler.rb b/railties/lib/rails/commands/profiler.rb index 7959d8a981..94cf32d32d 100644 --- a/railties/lib/rails/commands/profiler.rb +++ b/railties/lib/rails/commands/profiler.rb @@ -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" +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 -# 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) +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 |