Froze rails gems
[depot.git] / vendor / rails / actionpack / lib / action_controller / request_profiler.rb
diff --git a/vendor/rails/actionpack/lib/action_controller/request_profiler.rb b/vendor/rails/actionpack/lib/action_controller/request_profiler.rb
new file mode 100644 (file)
index 0000000..a6471d0
--- /dev/null
@@ -0,0 +1,169 @@
+require 'optparse'
+require 'action_controller/integration'
+
+module ActionController
+  class RequestProfiler
+    # Wrap up the integration session runner.
+    class Sandbox
+      include Integration::Runner
+
+      def self.benchmark(n, script)
+        new(script).benchmark(n)
+      end
+
+      def initialize(script_path)
+        @quiet = false
+        define_run_method(script_path)
+        reset!
+      end
+
+      def benchmark(n, profiling = false)
+        @quiet = true
+        print '  '
+
+        result = Benchmark.realtime do
+          n.times do |i|
+            run(profiling)
+            print_progress(i)
+          end
+        end
+
+        puts
+        result
+      ensure
+        @quiet = false
+      end
+
+      def say(message)
+        puts "  #{message}" unless @quiet
+      end
+
+      private
+        def define_run_method(script_path)
+          script = File.read(script_path)
+
+          source = <<-end_source
+            def run(profiling = false)
+              if profiling
+                RubyProf.resume do
+                  #{script}
+                end
+              else
+                #{script}
+              end
+
+              old_request_count = request_count
+              reset!
+              self.request_count = old_request_count
+            end
+          end_source
+
+          instance_eval source, script_path, 1
+        end
+
+        def print_progress(i)
+          print "\n  " if i % 60 == 0
+          print ' ' if i % 10 == 0
+          print '.'
+          $stdout.flush
+        end
+    end
+
+
+    attr_reader :options
+
+    def initialize(options = {})
+      @options = default_options.merge(options)
+    end
+
+
+    def self.run(args = nil, options = {})
+      profiler = new(options)
+      profiler.parse_options(args) if args
+      profiler.run
+    end
+
+    def run
+      sandbox = Sandbox.new(options[:script])
+
+      puts 'Warming up once'
+
+      elapsed = warmup(sandbox)
+      puts '%.2f sec, %d requests, %d req/sec' % [elapsed, sandbox.request_count, sandbox.request_count / elapsed]
+      puts "\n#{options[:benchmark] ? 'Benchmarking' : 'Profiling'} #{options[:n]}x"
+
+      options[:benchmark] ? benchmark(sandbox) : profile(sandbox)
+    end
+
+    def profile(sandbox)
+      load_ruby_prof
+
+      benchmark(sandbox, true)
+      results = RubyProf.stop
+
+      show_profile_results results
+      results
+    end
+
+    def benchmark(sandbox, profiling = false)
+      sandbox.request_count = 0
+      elapsed = sandbox.benchmark(options[:n], profiling).to_f
+      count = sandbox.request_count.to_i
+      puts '%.2f sec, %d requests, %d req/sec' % [elapsed, count, count / elapsed]
+    end
+
+    def warmup(sandbox)
+      Benchmark.realtime { sandbox.run(false) }
+    end
+
+    def default_options
+      { :n => 100, :open => 'open %s &' }
+    end
+
+    # Parse command-line options
+    def parse_options(args)
+      OptionParser.new do |opt|
+        opt.banner = "USAGE: #{$0} [options] [session script path]"
+
+        opt.on('-n', '--times [100]', 'How many requests to process. Defaults to 100.') { |v| options[:n] = v.to_i if v }
+        opt.on('-b', '--benchmark', 'Benchmark instead of profiling') { |v| options[:benchmark] = v }
+        opt.on('-m', '--measure [mode]', 'Which ruby-prof measure mode to use: process_time, wall_time, cpu_time, allocations, or memory. Defaults to process_time.') { |v| options[:measure] = v }
+        opt.on('--open [CMD]', 'Command to open profile results. Defaults to "open %s &"') { |v| options[:open] = v }
+        opt.on('-h', '--help', 'Show this help') { puts opt; exit }
+
+        opt.parse args
+
+        if args.empty?
+          puts opt
+          exit
+        end
+        options[:script] = args.pop
+      end
+    end
+
+    protected
+      def load_ruby_prof
+        begin
+          gem 'ruby-prof', '>= 0.6.1'
+          require 'ruby-prof'
+          if mode = options[:measure]
+            RubyProf.measure_mode = RubyProf.const_get(mode.upcase)
+          end
+        rescue LoadError
+          abort '`gem install ruby-prof` to use the profiler'
+        end
+      end
+
+      def show_profile_results(results)
+        File.open "#{RAILS_ROOT}/tmp/profile-graph.html", 'w' do |file|
+          RubyProf::GraphHtmlPrinter.new(results).print(file)
+          `#{options[:open] % file.path}` if options[:open]
+        end
+
+        File.open "#{RAILS_ROOT}/tmp/profile-flat.txt", 'w' do |file|
+          RubyProf::FlatPrinter.new(results).print(file)
+          `#{options[:open] % file.path}` if options[:open]
+        end
+      end
+  end
+end