From f36c46754fa420343e7b01695f09e62293a40597 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Fri, 25 Jul 2014 12:09:49 -0500 Subject: Encapsulate tools/profile functionality in CodeTools::Profiler Fix bug in path expansion of input filepath [ci skip] --- tools/profile | 128 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 52 deletions(-) (limited to 'tools') diff --git a/tools/profile b/tools/profile index d4b2fc5fbd..5c916aafc8 100755 --- a/tools/profile +++ b/tools/profile @@ -1,71 +1,95 @@ #!/usr/bin/env ruby # Example: -# ./profile ../activesupport/lib/active_support.rb [ruby-prof mode] +# tools/profile activesupport/lib/active_support.rb [ruby-prof mode] [ruby-prof printer] ENV['NO_RELOAD'] ||= '1' ENV['RAILS_ENV'] ||= 'development' -require 'benchmark' +module CodeTools + class Profiler -module RequireProfiler - private - def require(file, *args) RequireProfiler.profile(file) { super } end - def load(file, *args) RequireProfiler.profile(file) { super } end - - @depth, @stats = 0, [] - class << self - attr_accessor :depth - attr_accessor :stats - - def profile(file) - stats << [file, depth] - self.depth += 1 - result = nil - elapsed = Benchmark.realtime { result = yield } - self.depth -= 1 - stats.pop if stats.last.first == file - stats << [file, depth, elapsed] if result - result + attr_reader :path, :mode + def initialize(path, mode=nil) + @path, @mode = path, mode + require 'benchmark' end - end -end -GC.start -before_rss = `ps -o rss= -p #{Process.pid}`.to_i + def profile_requires + GC.start + before_rss = `ps -o rss= -p #{Process.pid}`.to_i -path = ARGV.shift -if mode = ARGV.shift - require 'ruby-prof' - RubyProf.measure_mode = RubyProf.const_get(mode.upcase) - RubyProf.start -else - Object.instance_eval { include RequireProfiler } -end + if mode + require 'ruby-prof' + RubyProf.measure_mode = RubyProf.const_get(mode.upcase) + RubyProf.start + else + Object.instance_eval { include RequireProfiler } + end + + elapsed = Benchmark.realtime { require path } + results = RubyProf.stop if mode -elapsed = Benchmark.realtime { require path } -results = RubyProf.stop if mode + GC.start + after_rss = `ps -o rss= -p #{Process.pid}`.to_i -GC.start -after_rss = `ps -o rss= -p #{Process.pid}`.to_i + if mode + if printer = ARGV.shift + puts "RubyProf outputting to stderr with printer #{printer}" + RubyProf.const_get("#{printer.to_s.classify}Printer").new(results).print($stdout) + elsif RubyProf.const_defined?(:CallStackPrinter) + filename = "#{File.basename(path, '.rb')}.#{mode}.html" + puts "RubyProf outputting to #{filename}" + File.open(filename, 'w') do |out| + RubyProf::CallStackPrinter.new(results).print(out) + end + else + filename = "#{File.basename(path, '.rb')}.#{mode}.callgrind" + puts "RubyProf outputting to #{filename}" + File.open(filename, 'w') do |out| + RubyProf::CallTreePrinter.new(results).print(out) + end + end + end -if mode - if printer = ARGV.shift - RubyProf.const_get("#{printer.to_s.classify}Printer").new(results).print($stdout) - elsif RubyProf.const_defined?(:CallStackPrinter) - File.open("#{File.basename(path, '.rb')}.#{mode}.html", 'w') do |out| - RubyProf::CallStackPrinter.new(results).print(out) + RequireProfiler.stats.each do |file, depth, sec| + if sec + puts "%8.1f ms %s%s" % [sec * 1000, ' ' * depth, file] + else + puts "#{' ' * (13 + depth)}#{file}" + end + end + puts "%8.1f ms %d KB RSS" % [elapsed * 1000, after_rss - before_rss] end - else - File.open("#{File.basename(path, '.rb')}.#{mode}.callgrind", 'w') do |out| - RubyProf::CallTreePrinter.new(results).print(out) + + module RequireProfiler + private + def require(file, *args) RequireProfiler.profile(file) { super } end + def load(file, *args) RequireProfiler.profile(file) { super } end + + @depth, @stats = 0, [] + class << self + attr_accessor :depth + attr_accessor :stats + + def profile(file) + stats << [file, depth] + self.depth += 1 + result = nil + elapsed = Benchmark.realtime { result = yield } + self.depth -= 1 + stats.pop if stats.last.first == file + stats << [file, depth, elapsed] if result + result + end + end end end end - -RequireProfiler.stats.each do |file, depth, sec| - if sec - puts "%8.1f ms %s%s" % [sec * 1000, ' ' * depth, file] +if $0 == __FILE__ + if (filename = ARGV.shift) + path = File.expand_path(filename) + mode = ARGV.shift + CodeTools::Profiler.new(path, mode).profile_requires else - puts "#{' ' * (13 + depth)}#{file}" + STDERR.puts "No file path entered. Usage is tools/profile path/to/file.rb [ruby-prof mode] [ruby-prof printer]" end end -puts "%8.1f ms %d KB RSS" % [elapsed * 1000, after_rss - before_rss] -- cgit v1.2.3