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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4d9be2e4ad16929b326e3a1e86c841ad0e13dc6
4
- data.tar.gz: 826eff5e56b4ae6c03c613dd9937a5ae396efa98
3
+ metadata.gz: ba362f7b8c12e89a30cc376280443aef51ce7ac6
4
+ data.tar.gz: 561f31e9f8b90a728dec5c9d6090f4bd7701228a
5
5
  SHA512:
6
- metadata.gz: 6153df14d977ffa0b1445950de2e779a8e8dd6606e665ad22bad348619b16659862bce078d1c12eb0d48f6bb90a5c0bd8ae73bc2c4d861466d6f16cda285d4c1
7
- data.tar.gz: 06ccf3dc44113e69b544aab7d9c4820daec59ec4b0d3b5e9784960d52b6ead75907f320d66cf4084319567f890862e4ab6954211e1b5c09d114f8553942e51ad
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
- three reporting modes are supported:
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 = 'stackprof-report [file.dump]+'
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 output (default)'){ options[:format] = :text }
15
- o.on('--callgrind'){ options[:format] = :callgrind }
16
- o.on('--graphviz'){ options[:format] = :graphviz }
17
- o.on('--file [grep]'){ |f| options[:format] = :file; options[:filter] = f }
18
- o.on('--files'){ |f| options[:format] = :files }
19
- o.on('--method [grep]'){ |f| options[:format] = :method; options[:filter] = f }
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('--sort-total'){ options[:sort] = true }
22
- o.on('--limit [num]', Integer){ |n| options[:limit] = n }
23
- end.parse!
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
@@ -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
- at_exit{ Middleware.save if Middleware.enabled? }
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: :cpu, interval: 1000) if self.class.enabled?
16
+ StackProf.start(mode: Middleware.mode, interval: Middleware.interval) if Middleware.enabled?
12
17
  @app.call(env)
13
18
  ensure
14
- StackProf.stop if self.class.enabled?
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", 'w') do |f|
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
@@ -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.to_i]] if other[:edges] && other[:edges].include?(frame.to_i) }.compact).any?
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.to_s][:name], weight] }
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.0'
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
@@ -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(mode: :cpu, interval: 100) do
103
- GC.start
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.0
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-23 00:00:00.000000000 Z
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: