mirror of https://github.com/rails/rails
Request profiler
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8016 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
96557eb35b
commit
d69be7df6d
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Request profiler. [Jeremy Kemper]
|
||||
|
||||
* Disabled checkboxes don't submit a form value. #9301 [vladr, robinjfisher]
|
||||
|
||||
* Added tests for options to ActiveRecordHelper#form. Closes #7213 [richcollins, mikong, mislav]
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
require 'optparse'
|
||||
|
||||
module ActionController
|
||||
class RequestProfiler
|
||||
# CGI with stubbed environment and standard input.
|
||||
class StubCGI < CGI
|
||||
attr_accessor :env_table, :stdinput
|
||||
|
||||
def initialize(env_table, stdinput)
|
||||
@env_table = env_table
|
||||
super
|
||||
@stdinput = stdinput
|
||||
end
|
||||
end
|
||||
|
||||
# Stripped-down dispatcher.
|
||||
class Sandbox
|
||||
attr_accessor :env, :body
|
||||
|
||||
def self.benchmark(n, env, body)
|
||||
Benchmark.realtime { n.times { new(env, body).dispatch } }
|
||||
end
|
||||
|
||||
def initialize(env, body)
|
||||
@env, @body = env, body
|
||||
end
|
||||
|
||||
def dispatch
|
||||
cgi = StubCGI.new(env, StringIO.new(body))
|
||||
|
||||
request = CgiRequest.new(cgi)
|
||||
response = CgiResponse.new(cgi)
|
||||
|
||||
controller = Routing::Routes.recognize(request)
|
||||
controller.process(request, response)
|
||||
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
|
||||
warmup
|
||||
options[:benchmark] ? benchmark : profile
|
||||
end
|
||||
|
||||
def profile
|
||||
load_ruby_prof
|
||||
|
||||
results = RubyProf.profile { benchmark }
|
||||
|
||||
show_profile_results results
|
||||
results
|
||||
end
|
||||
|
||||
def benchmark
|
||||
puts '%d req/sec' % (options[:n] / Sandbox.benchmark(options[:n], env, body))
|
||||
end
|
||||
|
||||
def warmup
|
||||
puts "#{options[:benchmark] ? 'Benchmarking' : 'Profiling'} #{options[:n]}x"
|
||||
puts "\nrequest headers: #{env.to_yaml}"
|
||||
|
||||
response = Sandbox.new(env, body).dispatch
|
||||
|
||||
puts "\nresponse body: #{response.body[0...100]}#{'[...]' if response.body.size > 100}"
|
||||
puts "\nresponse headers: #{response.headers.to_yaml}"
|
||||
puts
|
||||
end
|
||||
|
||||
|
||||
def uri
|
||||
URI.parse(options[:uri])
|
||||
rescue URI::InvalidURIError
|
||||
URI.parse(default_uri)
|
||||
end
|
||||
|
||||
def default_uri
|
||||
'/benchmarks/hello'
|
||||
end
|
||||
|
||||
def env
|
||||
@env ||= default_env
|
||||
end
|
||||
|
||||
def default_env
|
||||
defaults = {
|
||||
'HTTP_HOST' => "#{uri.host || 'localhost'}:#{uri.port || 3000}",
|
||||
'REQUEST_URI' => uri.path,
|
||||
'REQUEST_METHOD' => method,
|
||||
'CONTENT_LENGTH' => body.size }
|
||||
|
||||
if fixture = options[:fixture]
|
||||
defaults['CONTENT_TYPE'] = "multipart/form-data; boundary=#{extract_multipart_boundary(fixture)}"
|
||||
end
|
||||
|
||||
defaults
|
||||
end
|
||||
|
||||
def method
|
||||
options[:method] || (options[:fixture] ? 'POST' : 'GET')
|
||||
end
|
||||
|
||||
def body
|
||||
options[:fixture] ? File.read(options[:fixture]) : ''
|
||||
end
|
||||
|
||||
|
||||
def default_options
|
||||
{ :n => 1000, :open => 'open %s &' }
|
||||
end
|
||||
|
||||
# Parse command-line options
|
||||
def parse_options(args)
|
||||
OptionParser.new do |opt|
|
||||
opt.banner = "USAGE: #{$0} uri [options]"
|
||||
|
||||
opt.on('-u', '--uri [URI]', 'Request URI. Defaults to http://localhost:3000/benchmarks/hello') { |v| options[:uri] = v }
|
||||
opt.on('-n', '--times [0000]', 'How many requests to process. Defaults to 1000.') { |v| options[:n] = v.to_i }
|
||||
opt.on('--method [GET]', 'HTTP request method. Defaults to GET.') { |v| options[:method] = v.upcase }
|
||||
opt.on('--fixture [FILE]', 'Path to POST fixture file') { |v| options[:fixture] = v }
|
||||
opt.on('--benchmark', 'Benchmark instead of profiling') { |v| options[:benchmark] = 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
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def load_ruby_prof
|
||||
begin
|
||||
require 'ruby-prof'
|
||||
#RubyProf.measure_mode = RubyProf::ALLOCATED_OBJECTS
|
||||
rescue LoadError
|
||||
abort '`gem install ruby-prof` to use the profiler'
|
||||
end
|
||||
end
|
||||
|
||||
def extract_multipart_boundary(path)
|
||||
File.open(path) { |f| f.readline }
|
||||
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
|
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Request profiler. [Jeremy Kemper]
|
||||
|
||||
* config/boot.rb correctly detects RAILS_GEM_VERSION. #9834 [alexch, thewoolleyman]
|
||||
|
||||
* Fixed incorrect migration number if script/generate executed outside of Rails root #7080 [jeremymcanally]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/performance/request'
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env ruby
|
||||
RAILS_DEFAULT_LOGGER = nil
|
||||
require 'config/environment'
|
||||
require 'application'
|
||||
require 'action_controller/request_profiler'
|
||||
|
||||
ActionController::RequestProfiler.run(ARGV)
|
|
@ -67,7 +67,7 @@ class AppGenerator < Rails::Generator::Base
|
|||
m.file "environments/test.rb", "config/environments/test.rb"
|
||||
|
||||
# Scripts
|
||||
%w( about console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin ).each do |file|
|
||||
%w( about console destroy generate performance/benchmarker performance/profiler performance/request process/reaper process/spawner process/inspector runner server plugin ).each do |file|
|
||||
m.file "bin/#{file}", "script/#{file}", script_options
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue