perf_check 0.1.18 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|