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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e429268ea248d238130f873494e04bdf8b74a3fd
4
- data.tar.gz: 49cd55f1113f6f31492a84c273d58761d1ce824f
3
+ metadata.gz: 55dd84ea36a6406e768ed5581acf65b9f4b6aa50
4
+ data.tar.gz: fb5b16a1aea5f51c75af09c9843d4bd3a063ff30
5
5
  SHA512:
6
- metadata.gz: 263a12324d08e02724e6ef92703a02a0ea13e5cf07c846550189c628aaba177c5662492089745d6f172e5cab2ef5be7e46039ee6ed8100f6ebc8cf1f6bcd9872
7
- data.tar.gz: 56b851ddfd60cc6192c04cedafc2c715983cf01c930135da2881d2bacc5b62edc2eaac70092c68e2f2b14c404f9003f4596c8ba1ce893ba62a771669225138f6
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
- ENV['PERF_CHECK_NOCACHING'] = 'true'
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
- perf_check.print_results
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!!! >
@@ -32,7 +32,6 @@ class PerfCheck
32
32
  system('git stash -q >/dev/null')
33
33
  abort("Problem with git stash! Bailing...") unless $?.success?
34
34
  at_exit do
35
- system('git checkout .')
36
35
  Git.pop
37
36
  end
38
37
  end
@@ -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
@@ -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 = Rails.application.routes.recognize_path(login_route, :method => method)
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
@@ -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 :latencies, :cookie
7
- attr_accessor :this_latencies, :reference_latencies
8
+ attr_accessor :cookie, :this_response, :reference_response
9
+ attr_accessor :this_profiles, :reference_profiles
8
10
 
9
11
  def initialize(route)
10
- params = Rails.application.routes.recognize_path(route)
12
+ params = PerfCheck::Server.recognize_path(route)
11
13
 
12
- self.this_latencies = []
13
- self.reference_latencies = []
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
- print("\t"+'request #'.underline)
24
- print(" "+'latency'.underline)
25
- print(" "+'server rss'.underline)
26
- puts(" "+'profiler data'.underline)
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
- File.open("tmp/perf_check/failed_request.html", 'w') do |error_dump|
39
- error_dump.write(profile.response_body)
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
- self.latencies << profile.latency
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
- this_latencies.inject(0.0, :+) / this_latencies.size
84
+ this_profiles.map(&:latency).inject(0.0, :+) / this_profiles.size
59
85
  end
60
86
 
61
87
  def reference_latency
62
- reference_latencies.inject(0.0, :+) / reference_latencies.size
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.require_rails
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.latencies = x.reference_latencies }
71
+ test_cases.each{ |x| x.switch_to_reference_context }
61
72
  end
62
73
 
63
- test_cases.each do |test|
64
- server.restart
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
- puts("\n\nBenchmarking #{test.resource}:")
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.reference_latencies.empty?
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.6
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: