perf_check 0.0.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.
@@ -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: []