railsprof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dd676c3941cfebbd315805ed26916b228d3851e2
4
+ data.tar.gz: 0e3a3adfd11b13be3370e992d4b3f97e6713527a
5
+ SHA512:
6
+ metadata.gz: 94968394aacd9891748bc669235f6fea34760e08aef2fe7a56b02e3ed2f2c02a5b3085d95b13342c809c5af81dfb96bd94cd69d8408c15b7f1f3acd9c8c402ad
7
+ data.tar.gz: c6bb5b06f0b9928194699ef571c7dca8e8a22a8da3fe9b336465deee9e49bc40f3f5ab66749583fc73afcfd02ea75d049fec507022faaee0779871bb2e4b5d6f
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in railsprof.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Clifton King
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Railsprof
2
+
3
+ Rails CLI utility for profiling via rblineprof with good HTML output.
4
+
5
+ ![image](https://f.cloud.github.com/assets/14217/2202180/a8cd5ab4-98fc-11e3-8c1a-3ca127f26ae2.png)
6
+
7
+ ```
8
+ $ be railsprof -n5 -g hasherdashery -q key=REDACTED /api/v3/communities/123/portals
9
+ info App loading...
10
+ info App loaded in 12.02 secs
11
+ info Warmup #1 completed in 1133.25ms
12
+ info Profiling....
13
+ info Profile #1 completed in 467.55ms
14
+ info Profile #2 completed in 463.84ms
15
+ info Profile #3 completed in 447.02ms
16
+ info Profile #4 completed in 458.12ms
17
+ info Profile #5 completed in 448.42ms
18
+ info All profiles completed in 2287.82ms
19
+
20
+ -- Top files by execution time (total / child / excl / filename) --
21
+ 2230.80ms 2229.39ms 1.39ms app/controllers/api/v3/base_controller.rb
22
+ 2163.61ms 4285.14ms 0.59ms app/controllers/api/v3/communities_controller.rb
23
+ 2162.76ms 4174.57ms 110.10ms lib/api/interaction_responder.rb
24
+ 1988.38ms 1986.27ms 2.11ms lib/api/utilities.rb
25
+ 1986.27ms 3698.37ms 920.62ms hasherdashery-200a6c732704/lib/hasherdashery.rb
26
+ 1917.27ms 3330.16ms 545.64ms hasherdashery-200a6c732704/lib/hasherdashery/tailor.rb
27
+ 1668.67ms 2632.86ms 888.21ms hasherdashery-200a6c732704/lib/hasherdashery/property.rb
28
+ 1629.22ms 2307.68ms 1155.85ms hasherdashery-200a6c732704/lib/hasherdashery/value.rb
29
+ 1461.89ms 1849.78ms 1440.31ms hasherdashery-200a6c732704/lib/hasherdashery/data_type/base.rb
30
+ 1416.28ms 1838.26ms 301.43ms hasherdashery-200a6c732704/lib/hasherdashery/data_type/pattern.rb
31
+ 594.30ms 492.44ms 101.86ms hasherdashery-200a6c732704/lib/hasherdashery/dsl/pattern_maker.rb
32
+ 457.08ms 406.78ms 50.31ms lib/patterns/api/v3/common_patterns.rb
33
+ 424.95ms 530.18ms 402.26ms hasherdashery-200a6c732704/lib/hasherdashery/dsl/common_methods.rb
34
+ 311.47ms 0.00ms 311.47ms lib/api/router.rb
35
+ 274.65ms 329.48ms 55.15ms lib/patterns/api/v3/portal_patterns.rb
36
+ 247.06ms 121.02ms 126.04ms hasherdashery-200a6c732704/lib/hasherdashery/dsl/simple_type_methods.rb
37
+ 229.35ms 142.72ms 86.63ms hasherdashery-200a6c732704/lib/hasherdashery/pattern_rack.rb
38
+ 176.25ms 182.78ms 100.57ms hasherdashery-200a6c732704/lib/hasherdashery/dsl/pin_method.rb
39
+ 161.32ms 20.78ms 140.54ms hasherdashery-200a6c732704/lib/hasherdashery/type_label.rb
40
+ 127.24ms 4.97ms 122.27ms hasherdashery-200a6c732704/lib/hasherdashery/type_universe.rb
41
+ 66.29ms 0.00ms 66.29ms hasherdashery-200a6c732704/lib/hasherdashery/label.rb
42
+ ```
43
+
44
+ ## Installation
45
+
46
+ Add this line to your application's Gemfile:
47
+
48
+ gem 'railsprof'
49
+
50
+ And then execute:
51
+
52
+ $ bundle
53
+
54
+ Or install it yourself as:
55
+
56
+ $ gem install railsprof
57
+
58
+ ## Usage
59
+
60
+ `bundle exec railsprof` from your Rails root.
61
+
62
+ ```
63
+ $ be railsprof
64
+ Usage: railsprof [options] [method] /path
65
+ -h, --help Show this message
66
+ --version Show version
67
+ -v, --verbose Run verbosely
68
+ -e, --environment ENV Environment (defaults to RAILS_ENV)
69
+ -q, --query-param KEY=VAL Add query paramter (-q key=val {key: "val"}
70
+ -w, --warmups N Number of warmup runs on stack, default 1
71
+ -n, --num-runs N Number of runs in profiling mode, default 1
72
+ -t, --threshold N Threshold for file output in millis, default: 0.5
73
+ -d, --directory DIR Local paths to profile, default: app, lib, config
74
+ -g, --gem GEM Gems to profile, default:
75
+ ```
76
+
77
+ ## Contributing
78
+
79
+ 1. Fork it ( http://github.com/orgsync/railsprof/fork )
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
82
+ 4. Push to the branch (`git push origin my-new-feature`)
83
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/railsprof ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'railsprof'
3
+ require 'railsprof/cli'
4
+
5
+ Railsprof::CLI.start
@@ -0,0 +1,137 @@
1
+ require 'optparse'
2
+
3
+ class Railsprof::CLI
4
+ def self.start
5
+ logger = Railsprof::Logger.new(STDOUT)
6
+ logger.level = Logger::INFO
7
+ options = {}
8
+
9
+ opt_parser = OptionParser.new do |opts|
10
+ opts.banner = 'Usage: railsprof [options] /path'
11
+
12
+ opts.on('-h', '--help', 'Show this message') do
13
+ puts opts.help
14
+ exit
15
+ end
16
+
17
+ opts.on('--version', 'Show version') do
18
+ puts "Version #{Railsprof::VERSION}"
19
+ exit
20
+ end
21
+
22
+ opts.on('-v', '--verbose',
23
+ 'Run verbosely') do
24
+ logger.level = options[:log_level] = Logger::DEBUG
25
+ end
26
+
27
+ opts.on('-e', '--environment ENV',
28
+ 'Environment (defaults to RAILS_ENV)') do |env|
29
+ ENV['RAILS_ENV'] = env
30
+ end
31
+
32
+ opts.on('-q', '--query-param KEY=VAL',
33
+ 'Add query paramter (-q key=val {key: "val"}') do |q|
34
+ options[:params] ||= {}
35
+ key, val = q.split('=', 2)
36
+ options[:params][key] = val
37
+ end
38
+
39
+ # TODO add session support
40
+ # opts.on('-s', '--session KEY=VAL',
41
+ # 'Session info (-s user=3 --> {user: 3})') do |s|
42
+ # options[:session] ||= {}
43
+ # key, val = s.split('=', 2)
44
+
45
+ # # parse session value in ruby if possible
46
+ # options[:session][key.to_sym] =
47
+ # begin
48
+ # eval val
49
+ # rescue NameError
50
+ # val
51
+ # end
52
+
53
+ # logger.debug "Added to session: {#{key.to_sym.inspect} => #{val.inspect}}"
54
+ # end
55
+
56
+ # TODO add cookie support
57
+ # opts.on('-c', '--cookie KEY=VAL',
58
+ # 'Add cookie (-c remember=all --> {:remember => "all"})') do |s|
59
+ # options[:cookies] ||= {}
60
+ # key, val = s.split('=', 2)
61
+
62
+ # options[:cookies][key.to_sym] = val
63
+
64
+ # logger.debug "Added to cookiejar: {#{key.to_sym.inspect} => #{val.inspect}}"
65
+ # end
66
+
67
+ # TODO add host support
68
+ # opts.on('--host HOST',
69
+ # 'Host for request (--host www.blah.com)') do |h|
70
+ # options[:host] = h
71
+ # end
72
+
73
+ # TODO add port support
74
+ # opts.on('--port PORT',
75
+ # Integer,
76
+ # 'Port for request (--port 3000)') do |p|
77
+ # options[:port] = p
78
+ # end
79
+
80
+ opts.on('-w', '--warmups N', Integer,
81
+ 'Number of warmup runs on stack, default ' +
82
+ Railsprof::DEFAULT_OPTIONS[:warmups].to_s) do |w|
83
+ options[:warmups] = w
84
+ end
85
+
86
+ opts.on('-n', '--num-runs N', Integer,
87
+ 'Number of runs in profiling mode, default ' +
88
+ Railsprof::DEFAULT_OPTIONS[:runs].to_s) do |r|
89
+ options[:runs] = r
90
+ end
91
+
92
+ opts.on('-t', '--threshold N', Float,
93
+ 'Threshold for file output in millis, default: ' +
94
+ Railsprof::DEFAULT_OPTIONS[:threshold].to_s) do |t|
95
+ options[:threshold] = t
96
+ end
97
+
98
+ opts.on('-d', '--directory DIR',
99
+ 'Local paths to profile, default: ' +
100
+ Railsprof::DEFAULT_OPTIONS[:app_paths].join(', ')) do |d|
101
+ options[:app_dirs] ||= []
102
+ options[:app_dirs] << d
103
+ end
104
+
105
+ opts.on('-g', '--gem GEM',
106
+ 'Gems to profile, default: ' +
107
+ Railsprof::DEFAULT_OPTIONS[:gems].join(', ')) do |d|
108
+ options[:gems] ||= []
109
+ options[:gems] << d
110
+ end
111
+
112
+ # for capturing args before '--'
113
+ # opts.on do |h|
114
+ # puts "head: #{h.inspect}"
115
+ # end
116
+
117
+ # # for capturing args after '--'
118
+ # opts.on_tail do |t|
119
+ # puts "tail: #{t.inspect}"
120
+ # end
121
+
122
+ opts.on_tail("-h", "--help", "Show this message") do
123
+ puts opts
124
+ exit
125
+ end
126
+ end
127
+
128
+ args = opt_parser.parse!
129
+
130
+ if args.empty?
131
+ puts opt_parser.help
132
+ exit
133
+ end
134
+
135
+ Railsprof::Profiler.new(args, options).profile!
136
+ end
137
+ end
@@ -0,0 +1,78 @@
1
+ require 'erb'
2
+
3
+ class Railsprof::LineprofParser
4
+ # rblineprof formatting
5
+ # {
6
+ # "/path/to/file" => [
7
+ # # File stats (Line 0)
8
+ # [total_time, child_time, excl_time, total_cpu, child_cpu, excl_cpu],
9
+ # # Line 1 stats
10
+ # [wall, cpu, calls, allocations]
11
+ # # Line 2 stats
12
+ # [wall, cpu, calls, allocations]
13
+ # ...
14
+ # ]
15
+ # }
16
+
17
+ def initialize(profile, paths, threshold_ms: 0.5)
18
+ @threshold = threshold_ms * 1000
19
+ @paths = paths
20
+ @profile = profile
21
+ @friendly_paths = {}
22
+ @profiled_source = {}
23
+
24
+ @profiled_files = profile
25
+ .reduce([]) do |files, (file, lines)|
26
+ total = lines[0][0]
27
+ if total > @threshold # && !file[/benchmark|\.rake$/] # time in micros
28
+ @friendly_paths[file] = @paths.relative_path_for(file)
29
+ files << [file, *lines[0]]
30
+ end
31
+ files
32
+ end
33
+ .sort_by { |f| -f[1] }
34
+ end
35
+
36
+ def cli_report
37
+ puts "\n-- Top files by execution time (total / child / excl / filename) --\n"
38
+
39
+ @profiled_files.each do |file, total, child, excl|
40
+ printf "%9.2fms %9.2fms %9.2fms %s\n" %
41
+ [total / 1000.0, child / 1000.0, excl / 1000.0, @friendly_paths[file]]
42
+ end
43
+ end
44
+
45
+ def html_report
46
+ filename = [
47
+ '/tmp/railsprof',
48
+ File.basename(Dir.pwd),
49
+ Time.now.to_s(:number),
50
+ ].join('-') + '.html'
51
+
52
+ @profiled_files.each { |f, _| file_output(f) }
53
+
54
+ b = binding
55
+ template = File.read(File.dirname(__FILE__) +
56
+ '/views/railsprof-tmpl.html.erb')
57
+ ERB.new(template, 0, "", "@html_output").result(b)
58
+ File.open(filename, 'w') { |f| f.write(@html_output) }
59
+
60
+ `open #{filename}`
61
+ end
62
+
63
+ private
64
+
65
+ def file_output(file)
66
+ @profiled_source[file] = "\n % 8s + % 8s (called)\n" % %w(cpu idle)
67
+ File.readlines(file).each_with_index do |line, num|
68
+ wall, cpu, calls, _allocations = @profile[file][num + 1]
69
+ @profiled_source[file] <<
70
+ if calls && calls > 0
71
+ '% 8.1fms + % 8.1fms % 8s | %s' %
72
+ [cpu / 1000.0, (wall - cpu) / 1000.0, "(#{calls})", line]
73
+ else
74
+ ' | %s' % line
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,22 @@
1
+ require 'logger'
2
+
3
+ class Railsprof::Logger < ::Logger
4
+ SEVERITY_TO_COLOR_MAP = Hash[*%w(
5
+ DEBUG 0;37
6
+ INFO 32
7
+ WARN 33
8
+ FATAL 31
9
+ UKNOWN 37
10
+ )]
11
+
12
+ def initialize(*_)
13
+ super
14
+ self.formatter = ->(severity, datetime, progname, msg) {
15
+ [
16
+ "\033[#{SEVERITY_TO_COLOR_MAP[severity]}m",
17
+ '%-6s' % "#{severity.downcase}",
18
+ "\033[0m #{msg.strip}\n"
19
+ ].join
20
+ }
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ class Railsprof::Paths
2
+ def initialize(gems: [], app_paths: [])
3
+ @pwd = Pathname.new(Dir.pwd)
4
+ @gem_roots = Set.new
5
+ @paths =
6
+ app_paths.map { |d| [Dir.pwd, d].join('/') } +
7
+ gems.map { |g|
8
+ gem_dir = Gem::Specification.find_by_name(g).gem_dir
9
+ @gem_roots << Pathname.new(gem_dir).parent
10
+ gem_dir
11
+ }
12
+ end
13
+
14
+ def regexp
15
+ Regexp.new(
16
+ @paths.map { |p| Regexp.escape(p) }.join('|')
17
+ )
18
+ end
19
+
20
+ def relative_path_for(file)
21
+ path = Pathname.new(file)
22
+ if file[@pwd.to_s]
23
+ path.relative_path_from(@pwd)
24
+ elsif gem_root = @gem_roots.detect { |r| file[r.to_s] }
25
+ path.relative_path_from(gem_root)
26
+ else
27
+ file
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,230 @@
1
+ require 'active_support'
2
+ require 'active_support/benchmarkable'
3
+ require 'active_support/core_ext/hash'
4
+ require 'benchmark'
5
+ require 'rblineprof'
6
+ require 'railsprof/paths'
7
+ require 'railsprof/lineprof_parser'
8
+
9
+ class Railsprof::Profiler
10
+ attr_reader :logger, :options
11
+ attr_accessor :gem_roots
12
+
13
+ def initialize(args, opts = {})
14
+ @options = Railsprof::DEFAULT_OPTIONS.merge(opts)
15
+
16
+ @logger = options[:logger] || Railsprof::Logger.new(STDOUT)
17
+ @logger.level = options[:log_level] || Logger::INFO
18
+
19
+ @paths = Railsprof::Paths.new(options.slice(:gems, :app_paths))
20
+
21
+ args.unshift('GET') if args.size == 1
22
+
23
+ if args.size == 2
24
+ args.first.upcase!
25
+ @method, @path = args
26
+ else
27
+ fail ArgumentError "excepted METHOD PATH, received: #{args.join(' ')}"
28
+ end
29
+
30
+ logger.debug "Request: #@method #@path"
31
+ logger.debug "Options: #{options.inspect}"
32
+ end
33
+
34
+ def profile!
35
+ load_app!
36
+ options[:warmups].times do |i|
37
+ say_with_time("Warmup ##{i + 1}") { run }
38
+ end
39
+ if options[:runs] > 0
40
+ logger.info 'Profiling....'
41
+
42
+ say_with_time('All profiles') do
43
+ @profile = lineprof(@paths.regexp) do
44
+ options[:runs].times do |i|
45
+ say_with_time("Profile ##{i + 1}") { run }
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ parser = Railsprof::LineprofParser.new(
52
+ @profile, @paths,
53
+ threshold_ms: options[:threshold]
54
+ )
55
+
56
+ parser.cli_report
57
+ parser.html_report
58
+ end
59
+
60
+ def run
61
+ load_app!
62
+
63
+ begin
64
+ ret = Rails.application.routes.call(mock_request)
65
+ rescue Exception => e
66
+ if logger.level == Logger::DEBUG
67
+ raise e
68
+ else
69
+ logger.info "#{e.class.name} raised: #{e.message}"
70
+ logger.info "run railsprof with -v to see stacktrace"
71
+ exit 1
72
+ end
73
+ end
74
+
75
+ status, _ = ret
76
+ logger.warn "Status code #{status} received" if status != 200
77
+
78
+ ret
79
+ end
80
+
81
+ private
82
+
83
+ def mock_request
84
+ Rack::MockRequest.env_for(
85
+ @path,
86
+ method: @method,
87
+ params: options[:params]
88
+ # input: form body data
89
+ )
90
+ .merge({
91
+ # 'rack.session' => options[:session]
92
+ })
93
+ end
94
+
95
+ def load_app!
96
+ return if defined? @loaded
97
+
98
+ logger.info 'App loading...'
99
+ env_file = Dir.pwd + '/config/environment.rb'
100
+ if File.exists?(env_file)
101
+ ms = Benchmark.ms { load env_file }
102
+ logger.info 'App loaded in %.2f secs' % (ms / 1000.0)
103
+ else
104
+ puts 'Exiting... an application with config/environment.rb was expected'
105
+ exit 1
106
+ end
107
+ @loaded = true
108
+ end
109
+
110
+ def say_with_time(msg, level: 'info', &block)
111
+ ret = nil
112
+ ms = Benchmark.ms { ret = block.call }
113
+ logger.send(level, '%s completed in %.2fms' % [msg, ms])
114
+ ret
115
+ end
116
+ end
117
+
118
+ =begin
119
+ namespace :api do
120
+ GEMS = %w[hasherdashery active_interaction]
121
+ APP_DIRS = %w[lib app config gems]
122
+
123
+ desc 'profile an API endpoint, return rblineprof data'
124
+
125
+ task :profile, [:route] => :environment do |t, args|
126
+ route = args[:route]
127
+ status, headers, body = nil
128
+ gem_roots = Set.new
129
+
130
+ paths =
131
+ APP_DIRS.map { |d| Rails.root.join(d).to_s } +
132
+ GEMS.map { |g|
133
+ gem_dir = Gem::Specification.find_by_name(g).gem_dir
134
+ gem_roots << Pathname.new(gem_dir).parent
135
+ gem_dir
136
+ }
137
+
138
+ path_pattern = Regexp.new paths.map { |p| Regexp.escape(p) }.join('|')
139
+
140
+ print "Warming up request... "
141
+ warmup_ms = Benchmark.ms { status, headers, body = internal_request(route) }
142
+ printf "finished in %dms with status %s\n" % [warmup_ms, status]
143
+
144
+
145
+ profile = lineprof(path_pattern) do
146
+ status, headers, body = nil
147
+ print "Profiling request... "
148
+ profiled_ms = Benchmark.ms { status, headers, body = internal_request(route) }
149
+ printf "finished in %dms with status %s\n" % [profiled_ms, status]
150
+ end
151
+
152
+ # rblineprof formatting
153
+ # {
154
+ # "/path/to/file" => [
155
+ # # File stats
156
+ # [total_time, child_time, exclusive_time, allocations],
157
+ # # Line 1 stats
158
+ # [wall, cpu, calls, allocations]
159
+ # # Line 2 stats
160
+ # [wall, cpu, calls, allocations]
161
+ # ...
162
+ # ]
163
+ # }
164
+
165
+ friendly_paths = {}
166
+ profiled_source = {}
167
+
168
+ profiled_files = profile
169
+ .inject([]) do |files, (file, ((total, _, exclusive, allocs), _))|
170
+ if total > 500 && !file[/benchmark|\.rake$/] # time in micros
171
+ files << [file, total, exclusive, allocs]
172
+
173
+ path = Pathname.new(file)
174
+ friendly_paths[file] =
175
+ if file[Rails.root.to_s]
176
+ path.relative_path_from(Rails.root)
177
+ elsif gem_root = gem_roots.detect { |r| file[r.to_s] }
178
+ path.relative_path_from(gem_root)
179
+ else
180
+ file
181
+ end
182
+
183
+ profiled_source[file] = "\n"
184
+ File.readlines(file).each_with_index do |line, num|
185
+ wall, cpu, calls, allocations = profile[file][num + 1]
186
+ profiled_source[file] <<
187
+ if calls && calls > 0
188
+ '% 8.1fms + % 8.1fms (% 5d) | %s' %
189
+ [cpu / 1000.0, (wall - cpu) / 1000.0, calls, line]
190
+ else
191
+ ' | %s' % line
192
+ end
193
+ end
194
+ end
195
+ files
196
+ end
197
+ .sort_by { |f| -f[1] }
198
+
199
+ puts "\n-- Top files by execution time (ms / filename) --\n"
200
+
201
+ profiled_files.each do |file, total, exclusive, allocs|
202
+ printf "%8.3fms total %8.3fms excl %9d allocs %s \n" %
203
+ [total / 1000.0, exclusive / 1000.0, allocs, friendly_paths[file]]
204
+ end
205
+
206
+ filename = [
207
+ '/tmp/railsprof',
208
+ Rails.root.basename,
209
+ Time.now.to_s(:number),
210
+ ].join('-') + '.html'
211
+
212
+ b = binding
213
+ template = File.read('railsprof-tmpl.html.erb')
214
+ ERB.new(template, 0, "", "@html_output").result(b)
215
+
216
+ File.open(filename, 'w') { |f| f.write(@html_output) }
217
+
218
+ `open #{filename}`
219
+ end
220
+
221
+ def internal_request(path, params={})
222
+ request_env = Rack::MockRequest.env_for(path, params: params.to_query).merge({
223
+ # 'rack.session' => session
224
+ })
225
+
226
+ Rails.application.routes.call(request_env)
227
+ end
228
+ end
229
+ =end
230
+
@@ -0,0 +1,3 @@
1
+ module Railsprof
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,61 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= Rails.root.basename %> railsprof run</title>
5
+ <link href="http://clifton.is/css/normalize.css" rel="stylesheet" type="text/css">
6
+ <link href="http://clifton.is/css/highlight.github.css" rel="stylesheet" type="text/css">
7
+ <style>
8
+ pre {
9
+ overflow: auto;
10
+ word-wrap: normal;
11
+ white-space: pre;
12
+ }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <table>
17
+ <thead>
18
+ <tr>
19
+ <td width='120px'>Wall Total</td>
20
+ <td width='110px'>Wall Child</td>
21
+ <td width='110px'>Wall Excl</td>
22
+ <td width='90px'>CPU Total</td>
23
+ <td width='90px'>CPU Child</td>
24
+ <td width='90px'>CPU Excl</td>
25
+ <td>File</td>
26
+ </tr>
27
+ </thead>
28
+ <tbody>
29
+ <% @profiled_files.each do |file, *times| %>
30
+ <tr>
31
+ <% times.each do |t| %>
32
+ <td><%= t / 1000.0 %></td>
33
+ <% end %>
34
+ <td>
35
+ <a href='#' class='js-toggle-code' data-file='<%= file %>'>
36
+ <%= @friendly_paths[file] %>
37
+ </a>
38
+ </td>
39
+ </tr>
40
+ <tr style='display:none'>
41
+ <td colspan='7' style='overflow: auto'>
42
+ <br style='clear:both'>
43
+ <pre>
44
+ <code class="ruby"><%= @profiled_source[file] %></code>
45
+ </pre>
46
+ </td>
47
+ </tr>
48
+ <% end %>
49
+ </tbody>
50
+ </table>
51
+ <script src='http://code.jquery.com/jquery-1.11.0.min.js'></script>
52
+ <script src='http://clifton.is/js/highlight.js'></script>
53
+ <script>
54
+ hljs.initHighlightingOnLoad();
55
+ $('.js-toggle-code').on('click', function () {
56
+ $(this).parents('tr').next().toggle();
57
+ return false;
58
+ });
59
+ </script>
60
+ </body>
61
+ </html>
data/lib/railsprof.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'railsprof/version'
2
+ require 'railsprof/logger'
3
+ require 'railsprof/profiler'
4
+
5
+ module Railsprof
6
+ DEFAULT_OPTIONS = {
7
+ session: {},
8
+ cookies: {},
9
+ params: {},
10
+ warmups: 1,
11
+ runs: 1,
12
+ log_level: Logger::INFO,
13
+ threshold: 0.5,
14
+ app_paths: %w(app lib config),
15
+ gems: []
16
+ }
17
+ end
data/railsprof.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'railsprof/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'railsprof'
8
+ spec.version = Railsprof::VERSION
9
+ spec.authors = ['Clifton King']
10
+ spec.email = ['cliftonk@gmail.com']
11
+ spec.summary = 'command line rbline prof for rails apps'
12
+ # spec.description = %q{TODO: Write a longer description. Optional.}
13
+ spec.homepage = 'http://orgsync.github.io'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split("\n")
17
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ spec.test_files = `git ls-files -- spec/*`.split("\n").map{ |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '> 1.3'
22
+ # spec.add_development_dependency 'rspec', '~> 1.5'
23
+ spec.add_runtime_dependency 'rake', '~> 10.1.1'
24
+ spec.add_runtime_dependency 'rails', '> 3.0'
25
+ spec.add_runtime_dependency 'activesupport', '> 3.0'
26
+ spec.add_runtime_dependency 'rblineprof', '~> 0.3.6'
27
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: railsprof
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Clifton King
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>'
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>'
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 10.1.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 10.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>'
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>'
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>'
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>'
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rblineprof
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.6
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.3.6
83
+ description:
84
+ email:
85
+ - cliftonk@gmail.com
86
+ executables:
87
+ - railsprof
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/railsprof
97
+ - lib/railsprof.rb
98
+ - lib/railsprof/cli.rb
99
+ - lib/railsprof/lineprof_parser.rb
100
+ - lib/railsprof/logger.rb
101
+ - lib/railsprof/paths.rb
102
+ - lib/railsprof/profiler.rb
103
+ - lib/railsprof/version.rb
104
+ - lib/railsprof/views/railsprof-tmpl.html.erb
105
+ - railsprof.gemspec
106
+ homepage: http://orgsync.github.io
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.1.11
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: command line rbline prof for rails apps
130
+ test_files: []