aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorRafael Mendonça França <rafaelmfranca@gmail.com>2014-10-13 10:55:55 -0300
committerRafael Mendonça França <rafaelmfranca@gmail.com>2014-10-13 10:55:55 -0300
commit33361a50eb79fc63125be87508c48b31921b8027 (patch)
treed087e8245bb6fcbeb86f1f223232e34879ce704a /tools
parent664a0fa9cf461e7cf3e56c4928eb3c7aa6fe08dd (diff)
downloadrails-33361a50eb79fc63125be87508c48b31921b8027.tar.gz
rails-33361a50eb79fc63125be87508c48b31921b8027.tar.bz2
rails-33361a50eb79fc63125be87508c48b31921b8027.zip
Revert "Merge pull request #17247 from igas/fix-deprecations"
This reverts commit 997f1575f78bf6a2d12b8665a55807d51fe964df, reversing changes made to f919d5f5ea75f0e56a57643e5a0472367a98625f. See https://github.com/rails/rails/pull/17247#issuecomment-58895078
Diffstat (limited to 'tools')
-rwxr-xr-xtools/profile133
1 files changed, 133 insertions, 0 deletions
diff --git a/tools/profile b/tools/profile
new file mode 100755
index 0000000000..a35dd18b77
--- /dev/null
+++ b/tools/profile
@@ -0,0 +1,133 @@
+#!/usr/bin/env ruby
+# Example:
+# tools/profile activesupport/lib/active_support.rb [ruby-prof mode] [ruby-prof printer]
+ENV['NO_RELOAD'] ||= '1'
+ENV['RAILS_ENV'] ||= 'development'
+
+module CodeTools
+ class Profiler
+ Error = Class.new(StandardError)
+
+ attr_reader :path, :mode
+ def initialize(path, mode=nil)
+ assert_ruby_file_exists(path)
+ @path, @mode = path, mode
+ require 'benchmark'
+ end
+
+ def profile_requires
+ GC.start
+ before_rss = `ps -o rss= -p #{Process.pid}`.to_i
+
+ 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
+
+ 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
+
+ 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
+
+ private
+
+ def assert_ruby_file_exists(path)
+ fail Error.new("No such file") unless File.exists?(path)
+ fail Error.new("#{path} is a directory") if File.directory?(path)
+ ruby_extension = File.extname(path) == '.rb'
+ ruby_executable = File.open(path, 'rb') {|f| f.readline } =~ [/\A#!.*ruby/]
+ fail Error.new("Not a ruby file") unless ruby_extension or ruby_executable
+ end
+
+ 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
+# ruby-prof printer name causes the third arg to be sent :classify
+# which is probably overkill if you already know the name of the ruby-prof
+# printer you want to use, e.g. Graph
+begin
+ require 'active_support/inflector'
+ require 'active_support/core_ext/string/inflections'
+rescue LoadError
+ STDERR.puts $!.message
+ class String
+ # File activesupport/lib/active_support/inflector/methods.rb, line 150
+ def classify
+ # strip out any leading schema name
+ camelize(self.sub(/.*\./, ''))
+ end
+ # File activesupport/lib/active_support/inflector/methods.rb, line 68
+ def camelize(uppercase_first_letter = true)
+ string = self
+ if uppercase_first_letter
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
+ else
+ string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { $&.downcase }
+ end
+ string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
+ end
+ end
+end
+if $0 == __FILE__
+ if (filename = ARGV.shift)
+ path = File.expand_path(filename)
+ mode = ARGV.shift
+ CodeTools::Profiler.new(path, mode).profile_requires
+ else
+ STDERR.puts "No file path entered. Usage is tools/profile path/to/file.rb [ruby-prof mode] [ruby-prof printer]"
+ end
+end