perf_check 0.1.6 → 0.1.7
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 +46 -4
- data/lib/perf_check/git.rb +0 -1
- data/lib/perf_check/railtie.rb +4 -0
- data/lib/perf_check/server.rb +46 -3
- data/lib/perf_check/test_case.rb +65 -23
- data/lib/perf_check.rb +51 -7
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55dd84ea36a6406e768ed5581acf65b9f4b6aa50
|
4
|
+
data.tar.gz: fb5b16a1aea5f51c75af09c9843d4bd3a063ff30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1377387b9ef80a3bbbc9128b4461bf89ffb189fcbee5f2f685becee729681affb51a193725a5bcc414f0ac9eb57176c010fb89bd4a1a403ee8194f33aadbabc0
|
7
|
+
data.tar.gz: 64d8c600ad45a422698f31717e0612a150f7899d7252cf60c4c9c9fb70f531e13445605a9783c126dcaa1c30b06d9c5706ccf19bab9651c1e612aa24b7f78ba5
|
data/bin/perf_check
CHANGED
@@ -8,7 +8,8 @@ options.login = nil
|
|
8
8
|
options.number_of_requests = 10
|
9
9
|
options.reference = 'master'
|
10
10
|
options.http_statuses = [200]
|
11
|
-
|
11
|
+
options.verify_responses = false
|
12
|
+
options.caching = true
|
12
13
|
|
13
14
|
opts = OptionParser.new do |opts|
|
14
15
|
opts.banner = "Usage: perf_check [options] [route ...]"
|
@@ -52,7 +53,11 @@ opts = OptionParser.new do |opts|
|
|
52
53
|
end
|
53
54
|
|
54
55
|
opts.on('--no-caching', 'Do not enable fragment caching') do
|
55
|
-
|
56
|
+
options.caching = false
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on('--fail-fast', '-f', 'Bail immediately on non-200 HTTP response') do
|
60
|
+
options[:fail_fast?] = true
|
56
61
|
end
|
57
62
|
|
58
63
|
opts.on('--302-success', 'Consider HTTP 302 code a successful request') do
|
@@ -63,6 +68,29 @@ opts = OptionParser.new do |opts|
|
|
63
68
|
options.http_statuses.delete(302)
|
64
69
|
end
|
65
70
|
|
71
|
+
opts.separator "\nMisc"
|
72
|
+
opts.on('--input FILE', '-i') do |input|
|
73
|
+
File.readlines(input).each do |resource|
|
74
|
+
ARGV << resource.strip
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on('--verify-responses',
|
79
|
+
'Check whether there is a diff between the responses of this and the reference branch') do
|
80
|
+
options.verify_responses = true
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on('--brief', '-b') do
|
84
|
+
options.brief = true
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on('--diff') do
|
88
|
+
options.diff = true
|
89
|
+
options.brief = true
|
90
|
+
options.verify_responses = true
|
91
|
+
options.number_of_requests = 1
|
92
|
+
end
|
93
|
+
|
66
94
|
opts.separator ''
|
67
95
|
opts.separator <<EOF
|
68
96
|
Usage examples:
|
@@ -70,6 +98,7 @@ Usage examples:
|
|
70
98
|
perf_check /user/45/posts
|
71
99
|
perf_check /user/45/posts -n5
|
72
100
|
perf_check /user/45/posts --standard
|
101
|
+
perf_check /user/45/posts --admin
|
73
102
|
|
74
103
|
Benchmark against a specific commit
|
75
104
|
perf_check /user/45/posts -r 0123abcdefg
|
@@ -77,11 +106,20 @@ Usage examples:
|
|
77
106
|
|
78
107
|
Benchmark the changes in the working tree
|
79
108
|
perf_check /user/45/posts -r HEAD
|
109
|
+
|
110
|
+
Benchmark and diff the output against master
|
111
|
+
perf_check /user/45/posts --verify-responses
|
112
|
+
|
113
|
+
Just diff the output on your branch with master
|
114
|
+
perf_check /user/45/posts --diff
|
115
|
+
|
116
|
+
Diff a bunch of urls listed in a file (newline seperated)
|
117
|
+
perf_check --diff --input FILE
|
80
118
|
EOF
|
81
119
|
end
|
82
120
|
opts.parse!
|
83
121
|
|
84
|
-
PerfCheck.require_rails
|
122
|
+
PerfCheck.require_rails(options)
|
85
123
|
|
86
124
|
ARGV.each do |route|
|
87
125
|
perf_check.add_test_case(route)
|
@@ -94,7 +132,11 @@ end
|
|
94
132
|
perf_check.sanity_check
|
95
133
|
perf_check.run
|
96
134
|
|
97
|
-
|
135
|
+
if options.brief
|
136
|
+
perf_check.print_brief_results
|
137
|
+
else
|
138
|
+
perf_check.print_results
|
139
|
+
end
|
98
140
|
|
99
141
|
# _______________________
|
100
142
|
# < You made it faster!!! >
|
data/lib/perf_check/git.rb
CHANGED
data/lib/perf_check/railtie.rb
CHANGED
@@ -21,6 +21,10 @@ class PerfCheck
|
|
21
21
|
config = ActiveSupport::Configurable::Configuration
|
22
22
|
config.send(:define_method, :perform_caching){ fragment_caching }
|
23
23
|
end
|
24
|
+
|
25
|
+
if ENV['PERF_CHECK'] && ENV['PERF_CHECK_VERIFICATION']
|
26
|
+
PerfCheck::Server.seed_random!
|
27
|
+
end
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
data/lib/perf_check/server.rb
CHANGED
@@ -12,7 +12,7 @@ class PerfCheck
|
|
12
12
|
|
13
13
|
def self.authorization_action(method, login_route, &block)
|
14
14
|
Rails.application.reload_routes!
|
15
|
-
p =
|
15
|
+
p = PerfCheck::Server.recognize_path(login_route, :method => method)
|
16
16
|
controller = "#{p[:controller]}_controller".classify.constantize
|
17
17
|
action = p[:action]
|
18
18
|
|
@@ -35,6 +35,49 @@ class PerfCheck
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def self.mounted_path(engine)
|
39
|
+
route = Rails.application.routes.routes.detect do |route|
|
40
|
+
route.app == engine
|
41
|
+
end
|
42
|
+
route && route.path
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.recognize_path(path, opts={})
|
46
|
+
Rails::Engine.subclasses.each do |engine|
|
47
|
+
if match = mounted_path(engine) =~ path
|
48
|
+
path = path.sub(match.to_s, '')
|
49
|
+
return engine.routes.recognize_path(path, opts)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Rails.application.routes.recognize_path(path, opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.seed_random!
|
56
|
+
# Seed random
|
57
|
+
srand(1)
|
58
|
+
|
59
|
+
# SecureRandom cannot be seeded, so we have to monkey patch it instead :\
|
60
|
+
def SecureRandom.hex(n=16)
|
61
|
+
'4' * n
|
62
|
+
end
|
63
|
+
|
64
|
+
def SecureRandom.random_bytes(n=16)
|
65
|
+
'4' * n
|
66
|
+
end
|
67
|
+
|
68
|
+
def SecureRandom.random_number(n=0)
|
69
|
+
n > 4 ? 4 : n
|
70
|
+
end
|
71
|
+
|
72
|
+
def SecureRandom.urlsafe_base64(n=16, padding=false)
|
73
|
+
'4' * (4*n / 3)
|
74
|
+
end
|
75
|
+
|
76
|
+
def SecureRandom.uuid
|
77
|
+
"00000000-0000-0000-0000-000000000004"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
38
81
|
def self.sign_cookie_data(key, data, opts={})
|
39
82
|
opts[:serializer] ||= Marshal
|
40
83
|
secret = Rails.application.config.secret_token
|
@@ -116,10 +159,10 @@ class PerfCheck
|
|
116
159
|
|
117
160
|
def restart
|
118
161
|
if !@running
|
119
|
-
$stderr.print "starting rails
|
162
|
+
$stderr.print "starting rails...\n"
|
120
163
|
start
|
121
164
|
else
|
122
|
-
$stderr.print "re-starting rails
|
165
|
+
$stderr.print "re-starting rails...\n"
|
123
166
|
exit
|
124
167
|
start
|
125
168
|
end
|
data/lib/perf_check/test_case.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'diffy'
|
4
|
+
|
3
5
|
class PerfCheck
|
4
6
|
class TestCase
|
5
7
|
attr_accessor :resource, :controller, :action, :format
|
6
|
-
attr_accessor :
|
7
|
-
attr_accessor :
|
8
|
+
attr_accessor :cookie, :this_response, :reference_response
|
9
|
+
attr_accessor :this_profiles, :reference_profiles
|
8
10
|
|
9
11
|
def initialize(route)
|
10
|
-
params =
|
12
|
+
params = PerfCheck::Server.recognize_path(route)
|
11
13
|
|
12
|
-
self.
|
13
|
-
self.
|
14
|
-
self.latencies = this_latencies
|
14
|
+
self.this_profiles = []
|
15
|
+
self.reference_profiles = []
|
15
16
|
|
16
17
|
self.controller = params[:controller].split('/')[-1]
|
17
18
|
self.action = params[:action]
|
@@ -19,11 +20,20 @@ class PerfCheck
|
|
19
20
|
self.resource = route
|
20
21
|
end
|
21
22
|
|
23
|
+
def switch_to_reference_context
|
24
|
+
@context = :reference
|
25
|
+
end
|
26
|
+
|
22
27
|
def run(server, options)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
unless options.diff
|
29
|
+
print("\t"+'request #'.underline)
|
30
|
+
print(" "+'latency'.underline)
|
31
|
+
print(" "+'server rss'.underline)
|
32
|
+
print(" "+'status'.underline)
|
33
|
+
puts(" "+'profiler data'.underline)
|
34
|
+
end
|
35
|
+
|
36
|
+
profiles = (@context == :reference) ? reference_profiles : this_profiles
|
27
37
|
|
28
38
|
headers = {'Cookie' => "#{cookie}"}
|
29
39
|
unless self.format
|
@@ -35,31 +45,47 @@ class PerfCheck
|
|
35
45
|
end
|
36
46
|
|
37
47
|
unless options.http_statuses.include? profile.response_code
|
38
|
-
|
39
|
-
|
48
|
+
if options.fail_fast?
|
49
|
+
File.open("tmp/perf_check/failed_request.html", 'w') do |error_dump|
|
50
|
+
error_dump.write(profile.response_body)
|
51
|
+
end
|
52
|
+
error = sprintf("\t%2i:\tFAILED! (HTTP %d)", i, profile.response_code)
|
53
|
+
puts(error.red.bold)
|
54
|
+
puts("\t The server responded with a non-2xx status for this request.")
|
55
|
+
puts("\t The response has been written to tmp/perf_check/failed_request.html")
|
56
|
+
exit(1)
|
40
57
|
end
|
41
|
-
error = sprintf("\t%2i:\tFAILED! (HTTP %d)", i, profile.response_code)
|
42
|
-
puts(error.red.bold)
|
43
|
-
puts("\t The server responded with a non-2xx status for this request.")
|
44
|
-
puts("\t The response has been written to tmp/perf_check/failed_request.html")
|
45
|
-
exit(1)
|
46
58
|
end
|
47
59
|
|
48
60
|
next if i.zero?
|
49
|
-
printf("\t%2i:\t %.1fms %4dMB\t %s\n",
|
50
|
-
i, profile.latency, server.mem, profile.profile_url)
|
51
61
|
|
52
|
-
|
62
|
+
if options.verify_responses
|
63
|
+
if i == 1
|
64
|
+
if @context == :reference
|
65
|
+
self.reference_response = profile.response_body
|
66
|
+
else
|
67
|
+
self.this_response = profile.response_body
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
unless options.diff
|
73
|
+
printf("\t%2i:\t %.1fms %4dMB\t %s\t %s\n",
|
74
|
+
i, profile.latency, server.mem,
|
75
|
+
profile.response_code, profile.profile_url)
|
76
|
+
end
|
77
|
+
|
78
|
+
profiles << profile
|
53
79
|
end
|
54
|
-
puts
|
80
|
+
puts unless options.diff # pretty!
|
55
81
|
end
|
56
82
|
|
57
83
|
def this_latency
|
58
|
-
|
84
|
+
this_profiles.map(&:latency).inject(0.0, :+) / this_profiles.size
|
59
85
|
end
|
60
86
|
|
61
87
|
def reference_latency
|
62
|
-
|
88
|
+
reference_profiles.map(&:latency).inject(0.0, :+) / reference_profiles.size
|
63
89
|
end
|
64
90
|
|
65
91
|
def latency_difference
|
@@ -70,6 +96,22 @@ class PerfCheck
|
|
70
96
|
reference_latency / this_latency
|
71
97
|
end
|
72
98
|
|
99
|
+
def response_diff
|
100
|
+
diff = Diffy::Diff.new(this_response, reference_response,
|
101
|
+
:diff => PerfCheck.diff_options)
|
102
|
+
if diff.to_s.empty?
|
103
|
+
OpenStruct.new(:changed? => false)
|
104
|
+
else
|
105
|
+
FileUtils.mkdir_p("#{Rails.root}/tmp/perf_check/diffs")
|
106
|
+
file = `mktemp -u "#{Rails.root}/tmp/perf_check/diffs/XXXXXXXXXX"`.strip
|
107
|
+
[:text, :html].each do |format|
|
108
|
+
ext = {:text => 'diff', :html => 'html'}[format]
|
109
|
+
File.open("#{file}.#{ext}", 'w'){ |f| f.write(diff.to_s(format)) }
|
110
|
+
end
|
111
|
+
OpenStruct.new(:changed? => true, :file => "#{file}.diff")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
73
115
|
def eql?(test)
|
74
116
|
resource == test.resource
|
75
117
|
end
|
data/lib/perf_check.rb
CHANGED
@@ -11,8 +11,19 @@ require 'colorize'
|
|
11
11
|
class PerfCheck
|
12
12
|
attr_accessor :options, :server, :test_cases
|
13
13
|
|
14
|
-
def self.
|
14
|
+
def self.diff_options
|
15
|
+
@@diff_options ||=
|
16
|
+
['-U3', '--ignore-matching-lines=/mini-profiler-resources/includes.js']
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.require_rails(options)
|
15
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
|
16
27
|
|
17
28
|
app_root = Dir.pwd
|
18
29
|
until app_root == '/' || File.exist?("#{app_root}/config/application.rb")
|
@@ -57,28 +68,59 @@ class PerfCheck
|
|
57
68
|
if i == 1
|
58
69
|
Git.stash_if_needed
|
59
70
|
Git.checkout_reference(options.reference)
|
60
|
-
test_cases.each{ |x| x.
|
71
|
+
test_cases.each{ |x| x.switch_to_reference_context }
|
61
72
|
end
|
62
73
|
|
63
|
-
|
64
|
-
|
74
|
+
server.restart
|
75
|
+
test_cases.each_with_index do |test, i|
|
76
|
+
server.restart unless i.zero? || options.diff
|
65
77
|
|
66
78
|
if options.login
|
67
79
|
test.cookie = server.login(options.login, test)
|
68
80
|
end
|
69
81
|
|
70
|
-
|
82
|
+
if options.diff
|
83
|
+
puts "Issuing #{test.resource}"
|
84
|
+
else
|
85
|
+
puts("\nBenchmarking #{test.resource}:")
|
86
|
+
end
|
71
87
|
test.run(server, options)
|
72
88
|
end
|
73
89
|
end
|
74
90
|
end
|
75
91
|
|
92
|
+
|
93
|
+
def print_diff_results(diff)
|
94
|
+
if diff.changed?
|
95
|
+
print(" Diff: #{diff.file}".bold.light_red)
|
96
|
+
else
|
97
|
+
print(" Diff: Output is identical!".bold.light_green)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def print_brief_results
|
102
|
+
test_cases.each do |test|
|
103
|
+
print(test.resource.ljust(40) + ': ')
|
104
|
+
|
105
|
+
codes = (test.this_profiles+test.reference_profiles).map(&:response_code).uniq
|
106
|
+
print("(HTTP "+codes.join(',')+") ")
|
107
|
+
|
108
|
+
printf('%.1fms', test.this_latency)
|
109
|
+
|
110
|
+
puts && next if test.reference_profiles.empty?
|
111
|
+
|
112
|
+
print(sprintf(' (%+5.1fms)', test.latency_difference).bold)
|
113
|
+
print_diff_results(test.response_diff) if options.verify_responses
|
114
|
+
puts
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
76
118
|
def print_results
|
77
119
|
puts("==== Results ====")
|
78
120
|
test_cases.each do |test|
|
79
|
-
puts(test.resource)
|
121
|
+
puts(test.resource.bold)
|
80
122
|
|
81
|
-
if test.
|
123
|
+
if test.reference_profiles.empty?
|
82
124
|
printf("your branch: ".rjust(15)+"%.1fms\n", test.this_latency)
|
83
125
|
next
|
84
126
|
end
|
@@ -110,6 +152,8 @@ class PerfCheck
|
|
110
152
|
puts("master: ".rjust(15) + "#{master_latency}")
|
111
153
|
puts("your branch: ".rjust(15)+ "#{this_latency}")
|
112
154
|
puts(("change: ".rjust(15) + "#{formatted_change}").bold.send(color))
|
155
|
+
|
156
|
+
print_diff_results(test.response_diff) if options.verify_responses
|
113
157
|
end
|
114
158
|
end
|
115
159
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perf_check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rubytune
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.7.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: diffy
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.0.5
|
27
41
|
description:
|
28
42
|
email:
|
29
43
|
executables:
|