perf_check 0.1.18 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/perf_check +20 -139
- data/lib/perf_check/git.rb +30 -17
- data/lib/perf_check/railtie.rb +12 -12
- data/lib/perf_check/server.rb +18 -71
- data/lib/perf_check/test_case.rb +26 -24
- data/lib/perf_check.rb +35 -151
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b748791510099f0d04eccd3624623f0f268484a1
|
4
|
+
data.tar.gz: ebd96c65c3d27d78bd64cf01727e1e5a476e1d89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee57d225bcd04131ddbc874688eb383db6ca7296c44372e4e49bb0ab1b22f77088715e7cef012321594516620ff5a40aff528c19891ff5af69af3d249dd1de16
|
7
|
+
data.tar.gz: 0e4426dc65b80ef2ac67f931f1c84eed0dbbe6e3957a3844072ab02b9d7f2733be7a168601dd7d12156bb2e23417fa105fce613d7b02a3996d0ac13231e057f4
|
data/bin/perf_check
CHANGED
@@ -2,157 +2,38 @@
|
|
2
2
|
|
3
3
|
require 'perf_check'
|
4
4
|
|
5
|
-
perf_check = PerfCheck.new
|
6
|
-
options = perf_check.options
|
7
|
-
options.login = nil
|
8
|
-
options.number_of_requests = 10
|
9
|
-
options.reference = 'master'
|
10
|
-
options.http_statuses = [200]
|
11
|
-
options.verify_responses = false
|
12
|
-
options.caching = true
|
13
|
-
|
14
5
|
ORIGINAL_ARGV = ARGV.clone
|
15
6
|
|
16
|
-
|
17
|
-
opts.banner = "Usage: perf_check [options] [route ...]"
|
18
|
-
|
19
|
-
opts.separator 'Login options:'
|
20
|
-
opts.on('--admin', 'Log in as admin user for route') do
|
21
|
-
options.login = :admin
|
22
|
-
end
|
23
|
-
|
24
|
-
opts.on('--standard', 'Log in as standard user for route') do
|
25
|
-
options.login = :standard
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on('--super', 'Log in as super user') do
|
29
|
-
options.login = :super
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on('--user USER', '-u', 'Log in as USER') do |user|
|
33
|
-
options.login = user
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on('--no-login', '-L', "Don't log in") do
|
37
|
-
options.login = nil
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.separator "\nBenchmark options:"
|
41
|
-
opts.on('--requests N', '-n',
|
42
|
-
'Use N requests in benchmark, defaults to 10') do |n|
|
43
|
-
options.number_of_requests = n.to_i
|
44
|
-
end
|
45
|
-
|
46
|
-
opts.on('--reference COMMIT', '-r',
|
47
|
-
'Benchmark against COMMIT instead of master') do |commit|
|
48
|
-
options.reference = commit
|
49
|
-
end
|
50
|
-
|
51
|
-
opts.on('--quick', '-q',
|
52
|
-
'Fire off 5 requests just on this branch, no comparison with master') do
|
53
|
-
options.number_of_requests = 5
|
54
|
-
options.reference = nil
|
55
|
-
end
|
56
|
-
|
57
|
-
opts.on('--no-caching', 'Do not enable fragment caching') do
|
58
|
-
options.caching = false
|
59
|
-
end
|
60
|
-
|
61
|
-
opts.on('--fail-fast', '-f', 'Bail immediately on non-200 HTTP response') do
|
62
|
-
options[:fail_fast?] = true
|
63
|
-
end
|
64
|
-
|
65
|
-
opts.on('--302-success', 'Consider HTTP 302 code a successful request') do
|
66
|
-
options.http_statuses.push(302)
|
67
|
-
end
|
68
|
-
|
69
|
-
opts.on('--302-failure', 'Consider HTTP 302 code an unsuccessful request') do
|
70
|
-
options.http_statuses.delete(302)
|
71
|
-
end
|
72
|
-
|
73
|
-
opts.separator "\nMisc"
|
74
|
-
opts.on('--input FILE', '-i') do |input|
|
75
|
-
File.readlines(input).each do |resource|
|
76
|
-
ARGV << resource.strip
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
opts.on('--verify-responses',
|
81
|
-
'Check whether there is a diff between the responses of this and the reference branch') do
|
82
|
-
options.verify_responses = true
|
83
|
-
end
|
7
|
+
perf_check = PerfCheck.new
|
84
8
|
|
85
|
-
|
86
|
-
|
87
|
-
end
|
9
|
+
at_exit do
|
10
|
+
cbdata = {}
|
88
11
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
options.verify_responses = true
|
93
|
-
options.number_of_requests = 1
|
12
|
+
if $!
|
13
|
+
cbdata[:error_message] = "#{$!.class}: #{$!.message}\n"
|
14
|
+
cbdata[:error_message] << $!.backtrace.map{|x| "\t#{x}"}.join("\n")
|
94
15
|
end
|
95
16
|
|
96
|
-
|
97
|
-
opts.separator <<EOF
|
98
|
-
Usage examples:
|
99
|
-
Benchmark PostController#index against master
|
100
|
-
perf_check /user/45/posts
|
101
|
-
perf_check /user/45/posts -n5
|
102
|
-
perf_check /user/45/posts --standard
|
103
|
-
perf_check /user/45/posts --admin
|
104
|
-
|
105
|
-
Benchmark against a specific commit
|
106
|
-
perf_check /user/45/posts -r 0123abcdefg
|
107
|
-
perf_check /user/45/posts -r HEAD~2
|
108
|
-
|
109
|
-
Benchmark the changes in the working tree
|
110
|
-
perf_check /user/45/posts -r HEAD
|
111
|
-
|
112
|
-
Benchmark and diff the output against master
|
113
|
-
perf_check /user/45/posts --verify-responses
|
114
|
-
|
115
|
-
Just diff the output on your branch with master
|
116
|
-
perf_check /user/45/posts --diff
|
117
|
-
|
118
|
-
Diff a bunch of urls listed in a file (newline seperated)
|
119
|
-
perf_check --diff --input FILE
|
120
|
-
EOF
|
17
|
+
perf_check.trigger_when_finished_callbacks(cbdata)
|
121
18
|
end
|
122
19
|
|
123
|
-
|
124
|
-
|
125
|
-
opts.parse!
|
20
|
+
PerfCheck.load_config
|
21
|
+
PerfCheck::Options.parse!
|
126
22
|
|
127
|
-
|
23
|
+
ARGV.each{ |route| perf_check.add_test_case(route) }
|
128
24
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
if perf_check.test_cases.empty?
|
134
|
-
abort(opts.help)
|
135
|
-
end
|
136
|
-
|
137
|
-
perf_check.trigger_before_start_callback
|
25
|
+
if perf_check.test_cases.empty?
|
26
|
+
abort(PerfCheck::Options.help)
|
27
|
+
end
|
138
28
|
|
139
|
-
|
140
|
-
perf_check.run
|
29
|
+
perf_check.run
|
141
30
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
ensure
|
149
|
-
cbdata = {}
|
150
|
-
if error
|
151
|
-
cbdata[:error_message] = "#{error.class}: #{error.message}\n"
|
152
|
-
cbdata[:error_message] << error.backtrace.map{|x| "\t#{x}"}.join("\n")
|
153
|
-
end
|
154
|
-
perf_check.trigger_when_finished_callback(cbdata)
|
155
|
-
raise error if error
|
31
|
+
if PerfCheck.config.brief
|
32
|
+
perf_check.print_brief_results
|
33
|
+
elsif PerfCheck.config.json
|
34
|
+
perf_check.print_json_results
|
35
|
+
else
|
36
|
+
perf_check.print_full_results
|
156
37
|
end
|
157
38
|
|
158
39
|
# _______________________
|
data/lib/perf_check/git.rb
CHANGED
@@ -11,28 +11,42 @@ class PerfCheck
|
|
11
11
|
def self.checkout_reference(reference='master')
|
12
12
|
checkout(reference)
|
13
13
|
at_exit do
|
14
|
-
|
15
|
-
Git.checkout_current_branch
|
14
|
+
logger.info ''
|
15
|
+
Git.checkout_current_branch(false)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.checkout_current_branch
|
20
|
-
checkout(@current_branch)
|
19
|
+
def self.checkout_current_branch(bundle=true)
|
20
|
+
checkout(@current_branch, bundle)
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.checkout(branch)
|
24
|
-
|
23
|
+
def self.checkout(branch, bundle=true)
|
24
|
+
logger.info("Checking out #{branch} and bundling... ")
|
25
25
|
`git checkout #{branch} --quiet`
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
|
27
|
+
unless $?.success?
|
28
|
+
logger.fatal("Problem with git checkout! Bailing...") && abort
|
29
|
+
end
|
30
|
+
|
31
|
+
`git submodule update --quiet`
|
32
|
+
|
33
|
+
if bundle
|
34
|
+
Bundler.with_clean_env{ `bundle` }
|
35
|
+
unless $?.success?
|
36
|
+
logger.fatal("Problem bundling! Bailing...") && abort
|
37
|
+
end
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
def self.stash_if_needed
|
32
42
|
if anything_to_stash?
|
33
|
-
|
43
|
+
logger.info("Stashing your changes... ")
|
34
44
|
system('git stash -q >/dev/null')
|
35
|
-
|
45
|
+
|
46
|
+
unless $?.success?
|
47
|
+
logger.fatal("Problem with git stash! Bailing...") && abort
|
48
|
+
end
|
49
|
+
|
36
50
|
at_exit do
|
37
51
|
Git.pop
|
38
52
|
end
|
@@ -46,13 +60,12 @@ class PerfCheck
|
|
46
60
|
end
|
47
61
|
|
48
62
|
def self.pop
|
49
|
-
|
63
|
+
logger.info("Git stash applying...")
|
50
64
|
system('git stash pop -q')
|
51
|
-
abort("Problem with git stash! Bailing...") unless $?.success?
|
52
|
-
end
|
53
|
-
end
|
54
65
|
|
55
|
-
|
56
|
-
|
66
|
+
unless $?.success?
|
67
|
+
logger.fatal("Problem with git stash! Bailing...") && abort
|
68
|
+
end
|
69
|
+
end
|
57
70
|
end
|
58
71
|
end
|
data/lib/perf_check/railtie.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
class PerfCheck
|
2
2
|
class Railtie < Rails::Railtie
|
3
|
+
config.before_initialize do |app|
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
if defined?(Rack::MiniProfiler) && ENV['PERF_CHECK']
|
5
|
+
if defined?(Rack::MiniProfiler)
|
7
6
|
# Integrate with rack-mini-profiler
|
8
7
|
tmp = "#{Rails.root}/tmp/perf_check/miniprofiler"
|
9
8
|
FileUtils.mkdir_p(tmp)
|
@@ -12,19 +11,20 @@ class PerfCheck
|
|
12
11
|
Rack::MiniProfiler::FileStore.new(:path => tmp)
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
config.send(:define_method, :cache_classes){ true }
|
14
|
+
# Force caching .... :\
|
15
|
+
config = Rails::Application::Configuration
|
16
|
+
config.send(:define_method, :cache_classes){ true }
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
18
|
+
fragment_caching = !ENV['PERF_CHECK_NOCACHING']
|
19
|
+
config = ActiveSupport::Configurable::Configuration
|
20
|
+
config.send(:define_method, :perform_caching){ fragment_caching }
|
24
21
|
|
25
|
-
if ENV['
|
22
|
+
if ENV['PERF_CHECK_VERIFICATION']
|
26
23
|
PerfCheck::Server.seed_random!
|
27
24
|
end
|
25
|
+
|
26
|
+
require 'perf_check/middleware'
|
27
|
+
app.middleware.use PerfCheck::Middleware
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
data/lib/perf_check/server.rb
CHANGED
@@ -6,54 +6,6 @@ require 'fileutils'
|
|
6
6
|
|
7
7
|
class PerfCheck
|
8
8
|
class Server
|
9
|
-
def self.authorization(&block)
|
10
|
-
define_method(:login, &block)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.authorization_action(method, login_route, &block)
|
14
|
-
Rails.application.reload_routes!
|
15
|
-
p = PerfCheck::Server.recognize_path(login_route, :method => method)
|
16
|
-
controller = "#{p[:controller]}_controller".classify.constantize
|
17
|
-
action = p[:action]
|
18
|
-
|
19
|
-
controller.send(:define_method, :get_perf_check_session, &block)
|
20
|
-
controller.send(:define_method, action) do
|
21
|
-
login = params[:login_symbol].presence.try(:to_sym) || params[:login]
|
22
|
-
get_perf_check_session(login, params[:route])
|
23
|
-
render :nothing => true
|
24
|
-
end
|
25
|
-
controller.send(:skip_before_filter, :verify_authenticity_token)
|
26
|
-
|
27
|
-
authorization do |login, route|
|
28
|
-
http = Net::HTTP.new(host, port)
|
29
|
-
params = login.is_a?(Symbol) ? "login_symbol=#{login}" : "login=#{login}"
|
30
|
-
if method == :post
|
31
|
-
response = http.post(login_route, params)
|
32
|
-
elsif method == :get
|
33
|
-
response = http.get(login_route+"?#{params}")
|
34
|
-
end
|
35
|
-
|
36
|
-
response['Set-Cookie']
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.mounted_path(engine)
|
41
|
-
route = Rails.application.routes.routes.detect do |route|
|
42
|
-
route.app == engine
|
43
|
-
end
|
44
|
-
route && route.path
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.recognize_path(path, opts={})
|
48
|
-
Rails::Engine.subclasses.each do |engine|
|
49
|
-
if match = mounted_path(engine) =~ path
|
50
|
-
path = path.sub(match.to_s, '')
|
51
|
-
return engine.routes.recognize_path(path, opts)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
Rails.application.routes.recognize_path(path, opts)
|
55
|
-
end
|
56
|
-
|
57
9
|
def self.seed_random!
|
58
10
|
# Seed random
|
59
11
|
srand(1)
|
@@ -80,27 +32,12 @@ class PerfCheck
|
|
80
32
|
end
|
81
33
|
end
|
82
34
|
|
83
|
-
def self.sign_cookie_data(key, data, opts={})
|
84
|
-
opts[:serializer] ||= Marshal
|
85
|
-
secret = Rails.application.config.secret_token
|
86
|
-
|
87
|
-
marshal = ActiveSupport::MessageVerifier.new(secret,
|
88
|
-
:serializer => opts[:serializer])
|
89
|
-
marshal_value = marshal.generate(data)
|
90
|
-
|
91
|
-
"#{key}=#{marshal_value}"
|
92
|
-
end
|
93
|
-
|
94
35
|
def initialize
|
95
36
|
at_exit do
|
96
|
-
exit
|
37
|
+
exit rescue nil
|
97
38
|
end
|
98
39
|
end
|
99
40
|
|
100
|
-
def login(login, route)
|
101
|
-
''
|
102
|
-
end
|
103
|
-
|
104
41
|
def pid
|
105
42
|
pidfile = 'tmp/pids/server.pid'
|
106
43
|
File.read(pidfile).to_i if File.exists?(pidfile)
|
@@ -130,14 +67,16 @@ class PerfCheck
|
|
130
67
|
response = nil
|
131
68
|
prepare_to_profile
|
132
69
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
70
|
+
http.start
|
71
|
+
response = yield(http)
|
72
|
+
http.finish
|
73
|
+
|
74
|
+
latency = 1000 * response['X-Runtime'].to_f
|
75
|
+
query_count = response['X-PerfCheck-Query-Count'].to_i
|
138
76
|
|
139
77
|
Profile.new.tap do |result|
|
140
78
|
result.latency = latency
|
79
|
+
result.query_count = query_count
|
141
80
|
result.profile_url = latest_profiler_url
|
142
81
|
result.response_body = response.body
|
143
82
|
result.response_code = response.code.to_i
|
@@ -153,6 +92,14 @@ class PerfCheck
|
|
153
92
|
end
|
154
93
|
|
155
94
|
def start
|
95
|
+
ENV['PERF_CHECK'] = '1'
|
96
|
+
if PerfCheck.config.verify_responses
|
97
|
+
ENV['PERF_CHECK_VERIFICATION'] = '1'
|
98
|
+
end
|
99
|
+
unless PerfCheck.config.caching
|
100
|
+
ENV['PERF_CHECK_NOCACHING'] = '1'
|
101
|
+
end
|
102
|
+
|
156
103
|
system('rails server -b 127.0.0.1 -d -p 3031 >/dev/null')
|
157
104
|
sleep(1.5)
|
158
105
|
|
@@ -161,10 +108,10 @@ class PerfCheck
|
|
161
108
|
|
162
109
|
def restart
|
163
110
|
if !@running
|
164
|
-
|
111
|
+
logger.info("starting rails...")
|
165
112
|
start
|
166
113
|
else
|
167
|
-
|
114
|
+
logger.info("re-starting rails...")
|
168
115
|
exit
|
169
116
|
start
|
170
117
|
end
|
data/lib/perf_check/test_case.rb
CHANGED
@@ -4,19 +4,13 @@ require 'diffy'
|
|
4
4
|
|
5
5
|
class PerfCheck
|
6
6
|
class TestCase
|
7
|
-
attr_accessor :resource
|
7
|
+
attr_accessor :resource
|
8
8
|
attr_accessor :cookie, :this_response, :reference_response
|
9
9
|
attr_accessor :this_profiles, :reference_profiles
|
10
10
|
|
11
11
|
def initialize(route)
|
12
|
-
params = PerfCheck::Server.recognize_path(route)
|
13
|
-
|
14
12
|
self.this_profiles = []
|
15
13
|
self.reference_profiles = []
|
16
|
-
|
17
|
-
self.controller = params[:controller]
|
18
|
-
self.action = params[:action]
|
19
|
-
self.format = params[:format]
|
20
14
|
self.resource = route
|
21
15
|
end
|
22
16
|
|
@@ -26,19 +20,14 @@ class PerfCheck
|
|
26
20
|
|
27
21
|
def run(server, options)
|
28
22
|
unless options.diff
|
29
|
-
|
30
|
-
print(" "+'latency'.underline)
|
31
|
-
print(" "+'server rss'.underline)
|
32
|
-
print(" "+'status'.underline)
|
33
|
-
puts(" "+'profiler data'.underline)
|
23
|
+
logger.info("\t"+['request', 'latency', 'server rss', 'status', 'queries', 'profiler data'].map(&:underline).join(" "))
|
34
24
|
end
|
35
25
|
|
36
26
|
profiles = (@context == :reference) ? reference_profiles : this_profiles
|
37
27
|
|
38
|
-
headers = {'Cookie' => "#{cookie}"}
|
39
|
-
|
40
|
-
|
41
|
-
end
|
28
|
+
headers = {'Cookie' => "#{cookie}".strip}
|
29
|
+
headers['Accept'] = 'text/html,application/xhtml+xml,application/xml'
|
30
|
+
|
42
31
|
(options.number_of_requests+1).times do |i|
|
43
32
|
profile = server.profile do |http|
|
44
33
|
http.get(resource, headers)
|
@@ -50,10 +39,10 @@ class PerfCheck
|
|
50
39
|
error_dump.write(profile.response_body)
|
51
40
|
end
|
52
41
|
error = sprintf("\t%2i:\tFAILED! (HTTP %d)", i, profile.response_code)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
42
|
+
logger.fatal(error.red.bold)
|
43
|
+
logger.fatal("\t The server responded with a non-2xx status for this request.")
|
44
|
+
logger.fatal("\t The response has been written to tmp/perf_check/failed_request.html")
|
45
|
+
abort
|
57
46
|
end
|
58
47
|
end
|
59
48
|
|
@@ -69,15 +58,19 @@ class PerfCheck
|
|
69
58
|
end
|
70
59
|
end
|
71
60
|
|
61
|
+
profile.server_memory = server.mem
|
62
|
+
|
72
63
|
unless options.diff
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
row = sprintf("\t%2i:\t %.1fms %4dMB\t %s\t %s",
|
65
|
+
i, profile.latency, profile.server_memory,
|
66
|
+
profile.response_code, profile.query_count, profile.profile_url)
|
67
|
+
logger.info(row)
|
76
68
|
end
|
77
69
|
|
78
70
|
profiles << profile
|
79
71
|
end
|
80
|
-
|
72
|
+
|
73
|
+
logger.info '' unless options.diff # pretty!
|
81
74
|
end
|
82
75
|
|
83
76
|
def this_latency
|
@@ -89,6 +82,15 @@ class PerfCheck
|
|
89
82
|
reference_profiles.map(&:latency).inject(0.0, :+) / reference_profiles.size
|
90
83
|
end
|
91
84
|
|
85
|
+
def this_query_count
|
86
|
+
this_profiles.map(&:query_count).inject(0, :+) / this_profiles.size
|
87
|
+
end
|
88
|
+
|
89
|
+
def reference_query_count
|
90
|
+
return nil if reference_profiles.empty?
|
91
|
+
reference_profiles.map(&:query_count).inject(0, :+) / reference_profiles.size
|
92
|
+
end
|
93
|
+
|
92
94
|
def latency_difference
|
93
95
|
this_latency - reference_latency
|
94
96
|
end
|
data/lib/perf_check.rb
CHANGED
@@ -1,56 +1,27 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
require 'optparse'
|
4
1
|
require 'net/http'
|
5
2
|
require 'digest'
|
6
3
|
require 'fileutils'
|
7
4
|
require 'benchmark'
|
8
5
|
require 'ostruct'
|
9
6
|
require 'colorize'
|
7
|
+
require 'json'
|
10
8
|
|
11
9
|
class PerfCheck
|
12
10
|
attr_accessor :options, :server, :test_cases
|
13
11
|
|
14
|
-
def self.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
ENV['PERF_CHECK'] = '1'
|
21
|
-
if options.verify_responses
|
22
|
-
ENV['PERF_CHECK_VERIFICATION'] = '1'
|
23
|
-
end
|
24
|
-
if !options.caching
|
25
|
-
ENV['PERF_CHECK_NOCACHING'] = '1'
|
26
|
-
end
|
12
|
+
def self.app_root
|
13
|
+
@app_root ||= begin
|
14
|
+
dir = Dir.pwd
|
15
|
+
until dir == '/' || File.exist?("#{dir}/config/application.rb")
|
16
|
+
dir = File.dirname(dir)
|
17
|
+
end
|
27
18
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
19
|
+
unless File.exist?("#{dir}/config/application.rb")
|
20
|
+
abort("perf_check should be run from a rails directory")
|
21
|
+
end
|
32
22
|
|
33
|
-
|
34
|
-
abort("perf_check should be run from a rails directory")
|
23
|
+
dir
|
35
24
|
end
|
36
|
-
|
37
|
-
require "#{app_root}/config/environment"
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.when_finished(&block)
|
41
|
-
@when_finished_callback = block
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.when_finished_callback
|
45
|
-
@when_finished_callback || proc{ |*args| }
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.before_start(&block)
|
49
|
-
@before_start_callback = block
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.before_start_callback
|
53
|
-
@before_start_callback || proc{ |*args| }
|
54
25
|
end
|
55
26
|
|
56
27
|
def initialize
|
@@ -60,139 +31,52 @@ class PerfCheck
|
|
60
31
|
end
|
61
32
|
|
62
33
|
def add_test_case(route)
|
63
|
-
route
|
64
|
-
test_cases.push(TestCase.new(route))
|
65
|
-
end
|
66
|
-
|
67
|
-
def sanity_check
|
68
|
-
if ENV['RAILS_ENV'] == 'production'
|
69
|
-
abort("perf_check cannot be run in the production environment")
|
70
|
-
end
|
71
|
-
|
72
|
-
if Git.current_branch == "master"
|
73
|
-
puts("Yo, profiling master vs. master isn't too useful, but hey, we'll do it")
|
74
|
-
end
|
75
|
-
|
76
|
-
puts "="*77
|
77
|
-
print "PERRRRF CHERRRK! Grab a ☕️ and don't touch your working tree "
|
78
|
-
puts "(we automate git)"
|
79
|
-
puts "="*77
|
34
|
+
test_cases.push(TestCase.new(route.sub(/^([^\/])/, '/\1')))
|
80
35
|
end
|
81
36
|
|
82
37
|
def run
|
83
|
-
|
84
|
-
if i == 1
|
85
|
-
Git.stash_if_needed
|
86
|
-
Git.checkout_reference(options.reference)
|
87
|
-
test_cases.each{ |x| x.switch_to_reference_context }
|
88
|
-
end
|
89
|
-
|
90
|
-
server.restart
|
91
|
-
test_cases.each_with_index do |test, i|
|
92
|
-
server.restart unless i.zero? || options.diff
|
93
|
-
|
94
|
-
if options.login
|
95
|
-
test.cookie = server.login(options.login, test)
|
96
|
-
end
|
97
|
-
|
98
|
-
if options.diff
|
99
|
-
puts "Issuing #{test.resource}"
|
100
|
-
else
|
101
|
-
puts("\nBenchmarking #{test.resource}:")
|
102
|
-
end
|
103
|
-
test.run(server, options)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def trigger_before_start_callback
|
109
|
-
PerfCheck.before_start_callback.call(self)
|
110
|
-
end
|
111
|
-
|
112
|
-
def trigger_when_finished_callback(data={})
|
113
|
-
data = data.merge(:current_branch => PerfCheck::Git.current_branch)
|
114
|
-
results = OpenStruct.new(data)
|
115
|
-
results[:ARGV] = ORIGINAL_ARGV
|
116
|
-
if test_cases.size == 1
|
117
|
-
results.current_latency = test_cases.first.this_latency
|
118
|
-
results.reference_latency = test_cases.first.reference_latency
|
119
|
-
end
|
120
|
-
PerfCheck.when_finished_callback.call(results)
|
121
|
-
end
|
122
|
-
|
123
|
-
def print_diff_results(diff)
|
124
|
-
if diff.changed?
|
125
|
-
print(" Diff: #{diff.file}".bold.light_red)
|
126
|
-
else
|
127
|
-
print(" Diff: Output is identical!".bold.light_green)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def print_brief_results
|
132
|
-
test_cases.each do |test|
|
133
|
-
print(test.resource.ljust(40) + ': ')
|
134
|
-
|
135
|
-
codes = (test.this_profiles+test.reference_profiles).map(&:response_code).uniq
|
136
|
-
print("(HTTP "+codes.join(',')+") ")
|
38
|
+
trigger_before_start_callbacks
|
137
39
|
|
138
|
-
|
40
|
+
profile_requests
|
139
41
|
|
140
|
-
|
42
|
+
if options.reference
|
43
|
+
Git.stash_if_needed
|
44
|
+
Git.checkout_reference(options.reference)
|
45
|
+
test_cases.each{ |x| x.switch_to_reference_context }
|
141
46
|
|
142
|
-
|
143
|
-
print_diff_results(test.response_diff) if options.verify_responses
|
144
|
-
puts
|
47
|
+
profile_requests
|
145
48
|
end
|
146
49
|
end
|
147
50
|
|
148
|
-
|
149
|
-
puts("==== Results ====")
|
150
|
-
test_cases.each do |test|
|
151
|
-
puts(test.resource.bold)
|
51
|
+
private
|
152
52
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
53
|
+
def profile_requests
|
54
|
+
server.restart
|
55
|
+
test_cases.each_with_index do |test, i|
|
56
|
+
server.restart unless i.zero? || options.diff
|
157
57
|
|
158
|
-
|
159
|
-
this_latency = sprintf('%.1fms', test.this_latency)
|
160
|
-
difference = sprintf('%+.1fms', test.latency_difference)
|
58
|
+
test.cookie = options.cookie
|
161
59
|
|
162
|
-
if
|
163
|
-
|
164
|
-
else
|
165
|
-
change_factor = test.this_latency / test.reference_latency
|
166
|
-
end
|
167
|
-
formatted_change = sprintf('%.1fx', change_factor)
|
168
|
-
|
169
|
-
percent_change = 100*(test.latency_difference / test.reference_latency).abs
|
170
|
-
if percent_change < 10
|
171
|
-
formatted_change = "yours is about the same"
|
172
|
-
color = :blue
|
173
|
-
elsif test.latency_difference < 0
|
174
|
-
formatted_change = "yours is #{formatted_change} faster!"
|
175
|
-
color = :green
|
60
|
+
if options.diff
|
61
|
+
logger.info("Issuing #{test.resource}")
|
176
62
|
else
|
177
|
-
|
178
|
-
|
63
|
+
logger.info ''
|
64
|
+
logger.info("Benchmarking #{test.resource}:")
|
179
65
|
end
|
180
|
-
formatted_change = difference + " (#{formatted_change})"
|
181
66
|
|
182
|
-
|
183
|
-
puts("your branch: ".rjust(15)+ "#{this_latency}")
|
184
|
-
puts(("change: ".rjust(15) + "#{formatted_change}").bold.send(color))
|
185
|
-
|
186
|
-
print_diff_results(test.response_diff) if options.verify_responses
|
67
|
+
test.run(server, options)
|
187
68
|
end
|
188
69
|
end
|
189
70
|
end
|
190
71
|
|
191
|
-
|
72
|
+
require 'perf_check/logger'
|
192
73
|
require 'perf_check/server'
|
193
74
|
require 'perf_check/test_case'
|
194
75
|
require 'perf_check/git'
|
76
|
+
require 'perf_check/config'
|
77
|
+
require 'perf_check/callbacks'
|
78
|
+
require 'perf_check/output'
|
195
79
|
|
196
|
-
if defined?(Rails)
|
80
|
+
if defined?(Rails) && ENV['PERF_CHECK']
|
197
81
|
require 'perf_check/railtie'
|
198
82
|
end
|