blob: 859588c7356103903e4b4980dc581d37f32449b6 (
plain) (
tree)
|
|
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
protected
def run_gc
GC.start
end
class Performer; 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
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 report
if @supported
super
else
'%20s: unsupported' % @metric.name
end
end
def record
return unless @supported
klasses = 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, 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
# Ruby 1.9 with GC::Profiler
if defined?(GC::Profiler)
def with_gc_stats
GC::Profiler.enable
GC.start
yield
ensure
GC::Profiler.disable
end
# Ruby 1.8 + ruby-prof wrapper (enable/disable stats for Benchmarker)
elsif GC.respond_to?(:enable_stats)
def with_gc_stats
GC.enable_stats
yield
ensure
GC.disable_stats
end
end
end
class Time < Base; 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 < Base
Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
# Ruby 1.9 + GCdata patch
if GC.respond_to?(:malloc_allocated_size)
def measure
GC.malloc_allocated_size / 1024.0
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_memory)
def measure
RubyProf.measure_memory / 1024.0
end
end
end
class Objects < Amount
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
# Ruby 1.9 + GCdata patch
if GC.respond_to?(:malloc_allocations)
def measure
GC.malloc_allocations
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_allocations)
def measure
RubyProf.measure_allocations
end
end
end
class GcRuns < Amount
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
# Ruby 1.9
if GC.respond_to?(:count)
def measure
GC.count
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_gc_runs)
def measure
RubyProf.measure_gc_runs
end
end
end
class GcTime < Time
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
# Ruby 1.9 with GC::Profiler
if defined?(GC::Profiler) && GC::Profiler.respond_to?(:total_time)
def measure
GC::Profiler.total_time
end
# Ruby 1.8 + ruby-prof wrapper
elsif RubyProf.respond_to?(:measure_gc_time)
def measure
RubyProf.measure_gc_time / 1000
end
end
end
end
end
end
end
|