stackprof 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +59 -1
- data/bin/stackprof +16 -11
- data/lib/stackprof/middleware.rb +17 -6
- data/lib/stackprof/report.rb +2 -6
- data/stackprof.gemspec +1 -2
- data/test/test_stackprof.rb +4 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba362f7b8c12e89a30cc376280443aef51ce7ac6
|
4
|
+
data.tar.gz: 561f31e9f8b90a728dec5c9d6090f4bd7701228a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85a79f6edbf81e520b90d4f35d615c475297acdfe7b5db4277b93bc1e342ac8cc2aebdd56990bca1e82258020f270d6c28bd2098df27f90f320c005da07e9cae
|
7
|
+
data.tar.gz: 7d17bca5d3f356f63d1eec962e40dd4e50520e4a7b2c602b748f94779a9fb147566cc4439ff3cc0c619a687e4eff6e2da5a997240f1542e09849802a4ee7e09a
|
data/README.md
CHANGED
@@ -5,6 +5,64 @@ a sampling call-stack profiler for ruby 2.1+
|
|
5
5
|
inspired heavily by [gperftools](https://code.google.com/p/gperftools/),
|
6
6
|
and written as a replacement for [perftools.rb](https://github.com/tmm1/perftools.rb)
|
7
7
|
|
8
|
+
### getting started
|
9
|
+
|
10
|
+
in ruby:
|
11
|
+
|
12
|
+
``` ruby
|
13
|
+
profile = StackProf.run(mode: :cpu) do
|
14
|
+
...
|
15
|
+
end
|
16
|
+
File.open('tmp/stackprof-cpu-myapp.dump', 'wb'){ |f| f.write Marshal.dump(profile) }
|
17
|
+
```
|
18
|
+
|
19
|
+
via rack:
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
use StackProf::Middleware, enabled: true,
|
23
|
+
mode: :cpu,
|
24
|
+
interval: 1000,
|
25
|
+
save_every: 5
|
26
|
+
```
|
27
|
+
|
28
|
+
reporting:
|
29
|
+
|
30
|
+
```
|
31
|
+
$ stackprof tmp/stackprof-cpu-*.dump --text --limit 1
|
32
|
+
==================================
|
33
|
+
Mode: cpu(1000)
|
34
|
+
Samples: 60395 (1.09% miss rate)
|
35
|
+
GC: 2851 (4.72%)
|
36
|
+
==================================
|
37
|
+
TOTAL (pct) SAMPLES (pct) FRAME
|
38
|
+
1660 (2.7%) 1595 (2.6%) String#blank?
|
39
|
+
|
40
|
+
$ stackprof tmp/stackprof-cpu-*.dump --method 'String#blank?'
|
41
|
+
String#blank? (gems/activesupport-2.3.14.github30/lib/active_support/core_ext/object/blank.rb:80)
|
42
|
+
samples: 1595 self (2.6%) / 1660 total (2.7%)
|
43
|
+
callers:
|
44
|
+
373 ( 41.0%) ApplicationHelper#current_user
|
45
|
+
192 ( 21.1%) ApplicationHelper#current_repository
|
46
|
+
callers:
|
47
|
+
803 ( 48.4%) Object#present?
|
48
|
+
code:
|
49
|
+
| 80 | def blank?
|
50
|
+
1225 (2.0%) / 1225 (2.0%) | 81 | self !~ /[^[:space:]]/
|
51
|
+
| 82 | end
|
52
|
+
|
53
|
+
$ stackprof tmp/stackprof-cpu-*.dump --method 'Object#present?'
|
54
|
+
Object#present? (gems/activesupport-2.3.14.github30/lib/active_support/core_ext/object/blank.rb:20)
|
55
|
+
samples: 59 self (0.1%) / 910 total (1.5%)
|
56
|
+
callees (851 total):
|
57
|
+
803 ( 94.4%) String#blank?
|
58
|
+
32 ( 3.8%) Object#blank?
|
59
|
+
16 ( 1.9%) NilClass#blank?
|
60
|
+
code:
|
61
|
+
| 20 | def present?
|
62
|
+
910 (1.5%) / 59 (0.1%) | 21 | !blank?
|
63
|
+
| 22 | end
|
64
|
+
```
|
65
|
+
|
8
66
|
### sampling
|
9
67
|
|
10
68
|
four sampling modes are supported:
|
@@ -68,7 +126,7 @@ the sum of the outbound edge weights is equal to total samples collected on that
|
|
68
126
|
|
69
127
|
### reporting
|
70
128
|
|
71
|
-
|
129
|
+
multiple reporting modes are supported:
|
72
130
|
- text
|
73
131
|
- dotgraph
|
74
132
|
- source annotation
|
data/bin/stackprof
CHANGED
@@ -8,19 +8,22 @@ options = {
|
|
8
8
|
:limit => 30
|
9
9
|
}
|
10
10
|
|
11
|
-
OptionParser.new(ARGV) do |o|
|
12
|
-
o.banner =
|
11
|
+
parser = OptionParser.new(ARGV) do |o|
|
12
|
+
o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
|
13
13
|
|
14
|
-
o.on('--text', 'Text
|
15
|
-
o.on('--
|
16
|
-
o.on('--
|
17
|
-
o.on('--file [grep]'){ |f| options[:format] = :file; options[:filter] = f }
|
18
|
-
o.on('--
|
19
|
-
o.on('--
|
14
|
+
o.on('--text', 'Text summary (default)'){ options[:format] = :text }
|
15
|
+
o.on('--method [grep]', 'Zoom into specified method'){ |f| options[:format] = :method; options[:filter] = f }
|
16
|
+
o.on('--files', 'List of files'){ |f| options[:format] = :files }
|
17
|
+
o.on('--file [grep]', 'Show annotated code for specified file'){ |f| options[:format] = :file; options[:filter] = f }
|
18
|
+
o.on('--callgrind', 'Callgrind output (use with kcachegrind, gprof2dot)'){ options[:format] = :callgrind }
|
19
|
+
o.on('--graphviz', 'Graphviz output (use with dot)'){ options[:format] = :graphviz }
|
20
20
|
o.on('--debug'){ options[:format] = :debug }
|
21
|
-
o.on('--
|
22
|
-
o.on('--
|
23
|
-
end
|
21
|
+
o.on('--limit [num]', Integer, 'Limit --text output to N lines'){ |n| options[:limit] = n }
|
22
|
+
o.on('--sort-total', 'Sort --text output on total samples'){ options[:sort] = true }
|
23
|
+
end
|
24
|
+
|
25
|
+
parser.parse!
|
26
|
+
parser.abort(parser.help) if ARGV.empty?
|
24
27
|
|
25
28
|
reports = []
|
26
29
|
while ARGV.size > 0
|
@@ -31,6 +34,8 @@ report = reports.inject(:+)
|
|
31
34
|
case options[:format]
|
32
35
|
when :text
|
33
36
|
report.print_text(options[:sort], options[:limit])
|
37
|
+
when :debug
|
38
|
+
report.print_debug
|
34
39
|
when :callgrind
|
35
40
|
report.print_callgrind
|
36
41
|
when :graphviz
|
data/lib/stackprof/middleware.rb
CHANGED
@@ -2,26 +2,37 @@ require 'fileutils'
|
|
2
2
|
|
3
3
|
module StackProf
|
4
4
|
class Middleware
|
5
|
-
def initialize(app)
|
5
|
+
def initialize(app, options = {})
|
6
6
|
@app = app
|
7
|
-
|
7
|
+
@options = options
|
8
|
+
@num_reqs = options[:save_every] || nil
|
9
|
+
Middleware.mode = options[:mode] || :cpu
|
10
|
+
Middleware.interval = options[:interval] || 1000
|
11
|
+
Middleware.enabled = options[:enabled]
|
12
|
+
at_exit{ Middleware.save? } if options[:save_at_exit]
|
8
13
|
end
|
9
14
|
|
10
15
|
def call(env)
|
11
|
-
StackProf.start(mode:
|
16
|
+
StackProf.start(mode: Middleware.mode, interval: Middleware.interval) if Middleware.enabled?
|
12
17
|
@app.call(env)
|
13
18
|
ensure
|
14
|
-
|
19
|
+
if Middleware.enabled?
|
20
|
+
StackProf.stop
|
21
|
+
if @num_reqs && (@num_reqs-=1) == 0
|
22
|
+
@num_reqs = @options[:save_every]
|
23
|
+
Middleware.save
|
24
|
+
end
|
25
|
+
end
|
15
26
|
end
|
16
27
|
|
17
28
|
class << self
|
18
|
-
attr_accessor :enabled
|
29
|
+
attr_accessor :enabled, :mode, :interval
|
19
30
|
alias enabled? enabled
|
20
31
|
|
21
32
|
def save
|
22
33
|
if results = StackProf.results
|
23
34
|
FileUtils.mkdir_p('tmp')
|
24
|
-
File.open("tmp/stackprof-#{results[:mode]}-#{Process.pid}-#{Time.now.to_i}.dump", '
|
35
|
+
File.open("tmp/stackprof-#{results[:mode]}-#{Process.pid}-#{Time.now.to_i}.dump", 'wb') do |f|
|
25
36
|
f.write Marshal.dump(results)
|
26
37
|
end
|
27
38
|
end
|
data/lib/stackprof/report.rb
CHANGED
@@ -5,10 +5,6 @@ module StackProf
|
|
5
5
|
class Report
|
6
6
|
def initialize(data)
|
7
7
|
@data = data
|
8
|
-
|
9
|
-
frames = {}
|
10
|
-
@data[:frames].each{ |k,v| frames[k.to_s] = v }
|
11
|
-
@data[:frames] = frames
|
12
8
|
end
|
13
9
|
attr_reader :data
|
14
10
|
|
@@ -165,7 +161,7 @@ module StackProf
|
|
165
161
|
f.printf "%s (%s:%d)\n", info[:name], file, line
|
166
162
|
f.printf " samples: % 5d self (%2.1f%%) / % 5d total (%2.1f%%)\n", info[:samples], 100.0*info[:samples]/overall_samples, info[:total_samples], 100.0*info[:total_samples]/overall_samples
|
167
163
|
|
168
|
-
if (callers = data[:frames].map{ |id, other| [other[:name], other[:edges][frame
|
164
|
+
if (callers = data[:frames].map{ |id, other| [other[:name], other[:edges][frame]] if other[:edges] && other[:edges].include?(frame) }.compact).any?
|
169
165
|
f.puts " callers:"
|
170
166
|
callers = callers.sort_by(&:last).reverse
|
171
167
|
callers.each do |name, weight|
|
@@ -175,7 +171,7 @@ module StackProf
|
|
175
171
|
|
176
172
|
if callees = info[:edges]
|
177
173
|
f.printf " callees (%d total):\n", info[:total_samples]-info[:samples]
|
178
|
-
callees = callees.map{ |k, weight| [data[:frames][k
|
174
|
+
callees = callees.map{ |k, weight| [data[:frames][k][:name], weight] }
|
179
175
|
callees.each do |name, weight|
|
180
176
|
f.printf " % 5d (% 8s) %s\n", weight, "%3.1f%%" % (100.0*weight/(info[:total_samples]-info[:samples])), name
|
181
177
|
end
|
data/stackprof.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'stackprof'
|
3
|
-
s.version = '0.2.
|
3
|
+
s.version = '0.2.1'
|
4
4
|
s.homepage = 'http://github.com/tmm1/stackprof'
|
5
5
|
|
6
6
|
s.authors = 'Aman Gupta'
|
@@ -17,6 +17,5 @@ Gem::Specification.new do |s|
|
|
17
17
|
|
18
18
|
s.license = 'MIT'
|
19
19
|
|
20
|
-
# s.add_dependency 'yajl-ruby'
|
21
20
|
s.add_development_dependency 'rake-compiler'
|
22
21
|
end
|
data/test/test_stackprof.rb
CHANGED
@@ -58,7 +58,6 @@ class StackProfTest < Test::Unit::TestCase
|
|
58
58
|
assert_operator profile[:samples], :>, 1
|
59
59
|
frame = profile[:frames].values.first
|
60
60
|
assert_equal "block in StackProfTest#math", frame[:name]
|
61
|
-
File.open('/tmp/cputime.dump','w'){|f| f.write Marshal.dump(profile) }
|
62
61
|
end
|
63
62
|
|
64
63
|
def test_walltime
|
@@ -99,8 +98,10 @@ class StackProfTest < Test::Unit::TestCase
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def test_gc
|
102
|
-
profile = StackProf.run(
|
103
|
-
|
101
|
+
profile = StackProf.run(interval: 100) do
|
102
|
+
5.times do
|
103
|
+
GC.start
|
104
|
+
end
|
104
105
|
end
|
105
106
|
|
106
107
|
assert_empty profile[:frames]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stackprof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -66,8 +66,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
66
|
version: '0'
|
67
67
|
requirements: []
|
68
68
|
rubyforge_project:
|
69
|
-
rubygems_version: 2.2.0
|
69
|
+
rubygems_version: 2.2.0.rc.1
|
70
70
|
signing_key:
|
71
71
|
specification_version: 4
|
72
72
|
summary: sampling callstack-profiler for ruby 2.1+
|
73
73
|
test_files: []
|
74
|
+
has_rdoc:
|