Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Request profiler based on integration test scripts

  • Loading branch information...
commit 42b661f4fb65f2c0f8de4db7f46326acbb6dcdf7 0 parents
@lifo lifo authored
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 [name of plugin creator]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 README
@@ -0,0 +1,28 @@
+RequestProfiler
+===============
+
+Request profiler based on integration test scripts.
+
+Installation
+============
+
+ script/plugin install git://github.com/rails/request_profiler.git
+
+Example Script
+==============
+
+ # profile_script.rb
+ get '/'
+ post '/user', :user => { :login => 'rails' }
+
+Usage
+=====
+
+ script/performance/profiler profile_script.rb
+
+Options
+=======
+
+ script/performance/profiler --help
+
+Copyright (c) 2009 David Heinemeier Hansson, released under the MIT license
7 bin/request
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'config/environment'
+require 'application_controller'
+require 'action_controller/request_profiler'
+
+ActionController::RequestProfiler.run(ARGV)
3  install.rb
@@ -0,0 +1,3 @@
+dest = File.join(RAILS_ROOT, "script/performance/request")
+FileUtils.cp File.join(File.dirname(__FILE__), 'bin/request'), dest
+FileUtils.chmod(0755, dest)
168 lib/action_controller/request_profiler.rb
@@ -0,0 +1,168 @@
+require 'optparse'
+
+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 ' '
+
+ ms = Benchmark.ms do
+ n.times do |i|
+ run(profiling)
+ print_progress(i)
+ end
+ end
+
+ puts
+ ms
+ 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 '%.0f ms, %d requests, %d req/sec' % [elapsed, sandbox.request_count, 1000 * 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)
+ count = sandbox.request_count.to_i
+ puts '%.0f ms, %d requests, %d req/sec' % [elapsed, count, 1000 * count / elapsed]
+ end
+
+ def warmup(sandbox)
+ Benchmark.ms { 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
6 lib/command/performance/request.rb
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+require 'config/environment'
+require 'application'
+require 'action_controller/request_profiler'
+
+ActionController::RequestProfiler.run(ARGV)
Please sign in to comment.
Something went wrong with that request. Please try again.