perf_check 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ad9b614a45f9c940d13bb09e72a51cc2828b7bb0
4
+ data.tar.gz: f4bb7ee841ca754a94637afd3a9c60cf75200b8b
5
+ SHA512:
6
+ metadata.gz: 0eae9a892b51c88cbb0121560fd6c25e73167cf81847090d562057a057a087686bf486e398f2599309bb17f6f401e66a3252fbe8cbac52856aef6aa10a76a952
7
+ data.tar.gz: bf036d6e5baf5a8fd0d4e2f5c5aeb35f99e45c9b52ce598b2a8bc94c48f2fed78b3c5c2d4eae3a7f70bdb4c70a918ce271135daa5ce2c9416ced712809e808a5
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'perf_check'
4
+
5
+ perf_check = PerfCheck.new
6
+ options = perf_check.options
7
+ options.login = :admin
8
+ options.number_of_requests = 10
9
+ options.reference = 'master'
10
+
11
+ opts = OptionParser.new do |opts|
12
+ opts.banner = "Usage: perf_check [options] [route ...]"
13
+
14
+ opts.separator 'Login options:'
15
+ opts.on('--admin', 'Log in as admin user for route') do
16
+ options.login = :admin
17
+ end
18
+
19
+ opts.on('--standard', 'Log in as standard user for route') do
20
+ options.login = :standard
21
+ end
22
+
23
+ opts.on('--super', 'Log in as super user') do
24
+ options.login = :super
25
+ end
26
+
27
+ opts.on('--user USER', '-u', 'Log in as USER') do |user|
28
+ options.login = user
29
+ end
30
+
31
+ opts.on('--no-login', '-L', "Don't log in") do
32
+ options.login = nil
33
+ end
34
+
35
+ opts.separator "\nBenchmark options:"
36
+ opts.on('--requests N', '-n', 'Use N requests in benchmark, defaults to ') do |n|
37
+ options.number_of_requests = n.to_i
38
+ end
39
+
40
+ opts.on('--reference COMMIT', '-r',
41
+ 'Benchmark against COMMIT instead of master') do |commit|
42
+ options.reference = commit
43
+ end
44
+
45
+ opts.on('--quick', '-q',
46
+ 'Fire off 5 requests just on this branch, no comparison with master') do
47
+ options.number_of_requests = 5
48
+ options.reference = nil
49
+ end
50
+
51
+ opts.separator ''
52
+ opts.separator <<EOF
53
+ Usage examples:
54
+ Benchmark PostController#index against master
55
+ perf_check /user/45/posts
56
+ perf_check /user/45/posts -n5
57
+ perf_check /user/45/posts --standard
58
+
59
+ Benchmark against a specific commit
60
+ perf_check /user/45/posts -r 0123abcdefg
61
+ perf_check /user/45/posts -r HEAD~2
62
+
63
+ Benchmark the changes in the working tree
64
+ perf_check /user/45/posts -r HEAD
65
+ EOF
66
+ end
67
+ opts.parse!
68
+
69
+ app_root = Dir.pwd
70
+ until app_root == '/' || File.exist?("#{app_root}/config/application.rb")
71
+ app_root = File.dirname(app_root)
72
+ end
73
+
74
+ unless File.exist?("#{app_root}/config/application.rb")
75
+ abort("perf_check should be run from a rails directory")
76
+ end
77
+
78
+ ENV['RAILS_ENV'] = 'development'
79
+ ENV['PERF_CHECK'] = '1'
80
+ require File.expand_path("#{app_root}/config/environment")
81
+
82
+
83
+ ARGV.each do |route|
84
+ perf_check.add_test_case(route)
85
+ end
86
+
87
+ if perf_check.test_cases.empty?
88
+ abort(opts.help)
89
+ end
90
+
91
+ perf_check.sanity_check
92
+ perf_check.run
93
+
94
+ perf_check.print_results
95
+
96
+ # _______________________
97
+ # < You made it faster!!! >
98
+ # -----------------------
99
+ # o . .
100
+ # o / `. .' "
101
+ # o .---. < > < > .---.
102
+ # O | \ \ - ~ ~ - / / |
103
+ # _____ ..-~ ~-..-~
104
+ # | | \~~~\.' `./~~~/
105
+ # ========= \__/ R U B Y T U N E \__/
106
+ # .' O \ / / \ "
107
+ # (_____, `._.' | } \/~~~/
108
+ # `----. / } | / \__/
109
+ # `-. | / | / `. ,~~|
110
+ # ~-.__| /_ - ~ ^| /- _ `..-'
111
+ # | / | / ~-. `-. _ _ _
112
+ # |_____| |_____| ~ - . _ _ _ _ _>
113
+ #
@@ -0,0 +1,88 @@
1
+ # coding: utf-8
2
+
3
+ require 'optparse'
4
+ require 'net/http'
5
+ require 'digest'
6
+ require 'fileutils'
7
+ require 'benchmark'
8
+ require 'ostruct'
9
+
10
+ class PerfCheck
11
+ attr_accessor :options, :server, :test_cases
12
+
13
+ def initialize
14
+ self.options = OpenStruct.new
15
+ self.server = Server.new
16
+ self.test_cases = []
17
+ end
18
+
19
+ def add_test_case(route)
20
+ route = PerfCheck.normalize_resource(route)
21
+ test_cases.push(TestCase.new(route))
22
+ end
23
+
24
+ def sanity_check
25
+ if Git.current_branch == "master"
26
+ puts("Yo, profiling master vs. master isn't too useful, but hey, we'll do it")
27
+ end
28
+
29
+ puts "="*77
30
+ print "PERRRRF CHERRRK! Grab a ☕️ and don't touch your working tree "
31
+ puts "(we automate git)"
32
+ puts "="*77
33
+ end
34
+
35
+ def run
36
+ (options.reference ? 2 : 1).times do |i|
37
+ if i == 1
38
+ Git.stash_if_needed
39
+ Git.checkout_reference(options.reference)
40
+ test_cases.each{ |x| x.latencies = x.reference_latencies }
41
+ end
42
+
43
+ test_cases.each do |test|
44
+ server.restart
45
+ if options.login
46
+ test.cookie = server.login(options.login, test)
47
+ end
48
+
49
+ puts("\n\nBenchmarking #{test.resource}:")
50
+ test.run(server, options.number_of_requests)
51
+ end
52
+ end
53
+ end
54
+
55
+ def print_results
56
+ puts("==== Results ====")
57
+ test_cases.each do |test|
58
+ puts(test.resource)
59
+
60
+ if test.reference_latencies.empty?
61
+ printf("your branch: ".rjust(15)+"%.1fms\n", test.this_latency)
62
+ next
63
+ end
64
+
65
+ master_latency = sprintf('%.1fms', test.reference_latency)
66
+ this_latency = sprintf('%.1fms', test.this_latency)
67
+
68
+ difference = sprintf('%+.1fms', test.latency_difference)
69
+ if test.latency_difference < 0
70
+ formatted_change = sprintf('%.1fx', test.latency_factor)
71
+ formatted_change = "yours is #{formatted_change} faster!"
72
+ else
73
+ formatted_change = sprintf('%.1fx', 1.0 / test.latency_factor)
74
+ formatted_change = "yours is #{formatted_change} slower!!!"
75
+ end
76
+ formatted_change = difference + " (#{formatted_change})"
77
+
78
+ puts("master: ".rjust(15) + "#{master_latency}")
79
+ puts("your branch: ".rjust(15)+ "#{this_latency}")
80
+ puts("change: ".rjust(15) + "#{formatted_change}")
81
+ end
82
+ end
83
+ end
84
+
85
+
86
+ require 'perf_check/server'
87
+ require 'perf_check/test_case'
88
+ require 'perf_check/git'
@@ -0,0 +1,56 @@
1
+
2
+ class PerfCheck
3
+ class Git
4
+ # the branch we are on while loading the script
5
+ @current_branch = `git rev-parse --abbrev-ref HEAD`.strip
6
+
7
+ def self.current_branch
8
+ @current_branch
9
+ end
10
+
11
+ def self.checkout_reference(reference='master')
12
+ checkout(reference)
13
+ at_exit do
14
+ puts
15
+ Git.checkout_current_branch
16
+ end
17
+ end
18
+
19
+ def self.checkout_current_branch
20
+ checkout(@current_branch)
21
+ end
22
+
23
+ def self.checkout(branch)
24
+ print "Checking out #{branch}... "
25
+ `git checkout #{branch} --quiet`
26
+ puts "Problem with git checkout! Bailing..." and exit(1) unless $?.success?
27
+ end
28
+
29
+ def self.stash_if_needed
30
+ if anything_to_stash?
31
+ print("Stashing your changes... ")
32
+ system('git stash -q >/dev/null')
33
+ puts("Problem with git stash! Bailing...") and exit(1) unless $?.success?
34
+ at_exit do
35
+ Git.pop
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.anything_to_stash?
41
+ git_stash = `git diff`
42
+ git_stash << `git diff --staged`
43
+ !git_stash.empty?
44
+ end
45
+
46
+ def self.pop
47
+ puts("Git stash applying...")
48
+ system('git stash pop -q')
49
+ puts("Problem with git stash! Bailing...") and exit(1) unless $?.success?
50
+ end
51
+ end
52
+
53
+ def self.normalize_resource(resource)
54
+ resource.sub(/^([^\/])/, '/\1')
55
+ end
56
+ end
@@ -0,0 +1,117 @@
1
+
2
+ require 'net/http'
3
+ require 'benchmark'
4
+ require 'ostruct'
5
+ require 'fileutils'
6
+
7
+ class PerfCheck
8
+ class Server
9
+ def self.authorization(&block)
10
+ define_method(:login, &block)
11
+ end
12
+
13
+ def initialize
14
+ at_exit do
15
+ exit
16
+ end
17
+ end
18
+
19
+ def login(login, route)
20
+ ''
21
+ end
22
+
23
+ def pid
24
+ pidfile = 'tmp/pids/server.pid'
25
+ File.read(pidfile).to_i if File.exists?(pidfile)
26
+ end
27
+
28
+ def mem
29
+ mem = `ps -o rss= -p #{pid}`.strip.to_f / 1024
30
+ end
31
+
32
+ def prepare_to_profile
33
+ FileUtils.mkdir_p('tmp/perf_check/miniprofiler')
34
+ Dir["tmp/perf_check/miniprofiler/*"].each{|x| FileUtils.rm(x) }
35
+ end
36
+
37
+ def latest_profiler_url
38
+ mp_timer = Dir["tmp/perf_check/miniprofiler/mp_timers_*"].first
39
+ if "#{mp_timer}" =~ /mp_timers_(\w+)/
40
+ mp_link = "/mini-profiler-resources/results?id=#{$1}"
41
+ FileUtils.mkdir_p('tmp/miniprofiler')
42
+ FileUtils.mv(mp_timer, mp_timer.sub(/^tmp\/perf_check\//, 'tmp/'))
43
+ end
44
+ mp_link
45
+ end
46
+
47
+ def profile
48
+ http = Net::HTTP.new(host, port).tap{ |http| http.read_timeout = 1000 }
49
+ response = nil
50
+ prepare_to_profile
51
+
52
+ latency = 1000 * Benchmark.measure do
53
+ http.start
54
+ response = yield(http)
55
+ http.finish
56
+ end.real
57
+
58
+ case response.code
59
+ when '200'
60
+ Profile.new.tap do |result|
61
+ result.latency = latency
62
+ result.profile_url = latest_profiler_url
63
+ result.response_body = response.body
64
+ end
65
+ else
66
+ raise Server::ApplicationError.new(response) unless response.code == '200'
67
+ end
68
+ end
69
+
70
+ def exit
71
+ p = pid
72
+ if p
73
+ Process.kill('QUIT', pid)
74
+ sleep(1.5)
75
+ end
76
+ end
77
+
78
+ def start
79
+ system('rails server -b 127.0.0.1 -d -p 3031 >/dev/null')
80
+ sleep(1.5)
81
+
82
+ @running = true
83
+ end
84
+
85
+ def restart
86
+ if !@running
87
+ print "starting rails..."
88
+ start
89
+ else
90
+ print "re-starting rails..."
91
+ exit
92
+ start
93
+ end
94
+ end
95
+
96
+ def host
97
+ "127.0.0.1"
98
+ end
99
+
100
+ def port
101
+ 3031
102
+ end
103
+
104
+ class ApplicationError < Exception
105
+ def initialize(resp)
106
+ @response = resp
107
+ end
108
+ def code
109
+ @response.code
110
+ end
111
+ def body
112
+ @response.body
113
+ end
114
+ end
115
+ class Profile < OpenStruct; end
116
+ end
117
+ end
@@ -0,0 +1,73 @@
1
+ # coding: utf-8
2
+
3
+ class PerfCheck
4
+ class TestCase
5
+ attr_accessor :resource, :controller, :action
6
+ attr_accessor :latencies, :cookie
7
+ attr_accessor :this_latencies, :reference_latencies
8
+
9
+ def initialize(route)
10
+ params = Rails.application.routes.recognize_path(route)
11
+
12
+ self.this_latencies = []
13
+ self.reference_latencies = []
14
+ self.latencies = this_latencies
15
+
16
+ self.controller = params[:controller].split('/')[-1]
17
+ self.action = params[:action]
18
+ self.resource = route
19
+ end
20
+
21
+ def run(server, count)
22
+ (count+1).times do |i|
23
+ errors = 0
24
+ begin
25
+ profile = server.profile do |http|
26
+ http.get(resource, {'Cookie' => cookie})
27
+ end
28
+ rescue Server::ApplicationError => e
29
+ File.open("public/perf_check_failed_request.html", 'w') do |error_dump|
30
+ error_dump.write(e.body)
31
+ end
32
+ printf("\tRequest %2i: —— FAILURE (HTTP %s): %s\n",
33
+ i, e.code, '/perf_check_failed_request.html')
34
+ exit(1)
35
+ end
36
+
37
+ # Disregard initial request, since in dev. mode it includes
38
+ # all the autoload overhead (?)
39
+ next if i.zero?
40
+
41
+ printf("\tRequest %2i: %.1fms\t%4dMB\t%s\n",
42
+ i, profile.latency, server.mem, profile.profile_url)
43
+
44
+ self.latencies << profile.latency
45
+ end
46
+ puts
47
+ end
48
+
49
+ def this_latency
50
+ this_latencies.inject(0.0, :+) / this_latencies.size
51
+ end
52
+
53
+ def reference_latency
54
+ reference_latencies.inject(0.0, :+) / reference_latencies.size
55
+ end
56
+
57
+ def latency_difference
58
+ this_latency - reference_latency
59
+ end
60
+
61
+ def latency_factor
62
+ reference_latency / this_latency
63
+ end
64
+
65
+ def eql?(test)
66
+ resource == test.resource
67
+ end
68
+
69
+ def hash
70
+ resource.hash
71
+ end
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: perf_check
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - rubytune
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables:
16
+ - perf_check
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/perf_check
21
+ - lib/perf_check.rb
22
+ - lib/perf_check/git.rb
23
+ - lib/perf_check/server.rb
24
+ - lib/perf_check/test_case.rb
25
+ homepage: https://github.com/rubytune/perf_check
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: PERF CHECKKK!
49
+ test_files: []