aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/testing/performance/ruby.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/testing/performance/ruby.rb')
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby.rb152
1 files changed, 152 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/testing/performance/ruby.rb b/activesupport/lib/active_support/testing/performance/ruby.rb
new file mode 100644
index 0000000000..b29ec6719c
--- /dev/null
+++ b/activesupport/lib/active_support/testing/performance/ruby.rb
@@ -0,0 +1,152 @@
+begin
+ require 'ruby-prof'
+rescue LoadError
+ $stderr.puts 'Specify ruby-prof as application\'s dependency in Gemfile to run benchmarks.'
+ exit
+end
+
+module ActiveSupport
+ module Testing
+ module Performance
+ DEFAULTS.merge!(
+ if ARGV.include?('--benchmark')
+ { :metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time] }
+ else
+ { :min_percent => 0.01,
+ :metrics => [:process_time, :memory, :objects],
+ :formats => [:flat, :graph_html, :call_tree, :call_stack] }
+ end).freeze
+
+ protected
+ def run_gc
+ GC.start
+ end
+
+ class Profiler < Performer
+ def initialize(*args)
+ super
+ @supported = @metric.measure_mode rescue false
+ end
+
+ def run
+ return unless @supported
+
+ RubyProf.measure_mode = @metric.measure_mode
+ RubyProf.start
+ RubyProf.pause
+ full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
+ @data = RubyProf.stop
+ @total = @data.threads.values.sum(0) { |method_infos| method_infos.max.total_time }
+ end
+
+ def record
+ return unless @supported
+
+ klasses = full_profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
+
+ klasses.each do |klass|
+ fname = output_filename(klass)
+ FileUtils.mkdir_p(File.dirname(fname))
+ File.open(fname, 'wb') do |file|
+ klass.new(@data).print(file, full_profile_options.slice(:min_percent))
+ end
+ end
+ end
+
+ protected
+ def output_filename(printer_class)
+ suffix =
+ case printer_class.name.demodulize
+ when 'FlatPrinter'; 'flat.txt'
+ when 'FlatPrinterWithLineNumbers'; 'flat_line_numbers.txt'
+ when 'GraphPrinter'; 'graph.txt'
+ when 'GraphHtmlPrinter'; 'graph.html'
+ when 'GraphYamlPrinter'; 'graph.yml'
+ when 'CallTreePrinter'; 'tree.txt'
+ when 'CallStackPrinter'; 'stack.html'
+ when 'DotPrinter'; 'graph.dot'
+ else printer_class.name.sub(/Printer$/, '').underscore
+ end
+
+ "#{super()}_#{suffix}"
+ end
+ end
+
+ module Metrics
+ class Base
+ def measure_mode
+ self.class::Mode
+ end
+
+ def profile
+ RubyProf.resume
+ yield
+ ensure
+ RubyProf.pause
+ end
+
+ protected
+ # overridden by each implementation
+ def with_gc_stats
+ yield
+ end
+ end
+
+ class ProcessTime < Time
+ Mode = RubyProf::PROCESS_TIME if RubyProf.const_defined?(:PROCESS_TIME)
+
+ def measure
+ RubyProf.measure_process_time
+ end
+ end
+
+ class WallTime < Time
+ Mode = RubyProf::WALL_TIME if RubyProf.const_defined?(:WALL_TIME)
+
+ def measure
+ RubyProf.measure_wall_time
+ end
+ end
+
+ class CpuTime < Time
+ Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
+
+ def initialize(*args)
+ # FIXME: yeah my CPU is 2.33 GHz
+ RubyProf.cpu_frequency = 2.33e9 unless RubyProf.cpu_frequency > 0
+ super
+ end
+
+ def measure
+ RubyProf.measure_cpu_time
+ end
+ end
+
+ class Memory < DigitalInformationUnit
+ Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
+ end
+
+ class Objects < Amount
+ Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
+ end
+
+ class GcRuns < Amount
+ Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
+ end
+
+ class GcTime < Time
+ Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
+ end
+ end
+ end
+ end
+end
+
+if RUBY_VERSION.between?('1.9.2', '2.0')
+ require 'active_support/testing/performance/ruby/yarv'
+elsif RUBY_VERSION.between?('1.8.6', '1.9')
+ require 'active_support/testing/performance/ruby/mri'
+else
+ $stderr.puts 'Update your ruby interpreter to be able to run benchmarks.'
+ exit
+end