1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# Pass NEW=1 to run with the new Base
ENV['RAILS_ENV'] ||= 'production'
ENV['NO_RELOAD'] ||= '1'
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
require 'action_controller'
require 'action_controller/new_base' if ENV['NEW']
require 'action_view'
require 'benchmark'
class Runner
def initialize(app, output)
@app, @output = app, output
end
def puts(*)
super if @output
end
def call(env)
env['n'].to_i.times { @app.call(env) }
@app.call(env).tap { |response| report(env, response) }
end
def report(env, response)
return unless ENV["DEBUG"]
out = env['rack.errors']
out.puts response[0], response[1].to_yaml, '---'
response[2].each { |part| out.puts part }
out.puts '---'
end
def self.puts(*)
super if @output
end
def self.run(app, n, label, output = true)
@output = output
puts label, '=' * label.size if label
env = Rack::MockRequest.env_for("/").merge('n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout)
t = Benchmark.realtime { new(app, output).call(env) }
puts "%d ms / %d req = %.1f usec/req" % [10**3 * t, n, 10**6 * t / n]
puts
end
end
N = (ENV['N'] || 1000).to_i
module ActionController::Rails2Compatibility
instance_methods.each do |name|
remove_method name
end
end
class BasePostController < ActionController::Base
append_view_path "#{File.dirname(__FILE__)}/views"
def overhead
self.response_body = ''
end
def index
render :text => ''
end
def partial
render :partial => "/partial"
end
def many_partials
render :partial => "/many_partials"
end
def hundred_partials
render :partial => "/hundred_partials"
end
def partial_collection
render :partial => "/collection", :collection => [1,2,3,4,5,6,7,8,9,10]
end
def large_collection
render :partial => "/collection", :collection => (1...100).to_a
end
def show_template
render :template => "template"
end
end
OK = [200, {}, []]
MetalPostController = lambda { OK }
class HttpPostController < ActionController::Metal
def index
self.response_body = ''
end
end
ActionController::Base.use_accept_header = false
unless ENV["PROFILE"]
Runner.run(BasePostController.action(:overhead), N, 'overhead', false)
Runner.run(BasePostController.action(:index), N, 'index', false)
Runner.run(BasePostController.action(:partial), N, 'partial', false)
Runner.run(BasePostController.action(:many_partials), N, 'many_partials', false)
Runner.run(BasePostController.action(:partial_collection), N, 'collection', false)
Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials', false)
Runner.run(BasePostController.action(:large_collection), N, 'large_collection', false)
Runner.run(BasePostController.action(:show_template), N, 'template', false)
(ENV["M"] || 1).to_i.times do
Runner.run(BasePostController.action(:overhead), N, 'overhead')
Runner.run(BasePostController.action(:index), N, 'index')
Runner.run(BasePostController.action(:partial), N, 'partial')
Runner.run(BasePostController.action(:many_partials), N, 'many_partials')
Runner.run(BasePostController.action(:partial_collection), N, 'collection')
Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials')
Runner.run(BasePostController.action(:large_collection), N, 'large_collection')
Runner.run(BasePostController.action(:show_template), N, 'template')
end
else
Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"])
require "ruby-prof"
RubyProf.start
Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"])
result = RubyProf.stop
printer = RubyProf::CallStackPrinter.new(result)
printer.print(File.open("output.html", "w"))
end
|