stackprof 0.2.10 → 0.2.11
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -5
- data/Gemfile.lock +4 -1
- data/README.md +1 -0
- data/bin/stackprof +3 -2
- data/ext/stackprof/stackprof.c +154 -19
- data/lib/stackprof/flamegraph/flamegraph.js +926 -300
- data/lib/stackprof/flamegraph/viewer.html +29 -23
- data/lib/stackprof/report.rb +41 -0
- data/sample.rb +3 -3
- data/stackprof.gemspec +1 -1
- data/test/test_stackprof.rb +20 -17
- metadata +3 -4
@@ -5,9 +5,32 @@
|
|
5
5
|
body {
|
6
6
|
margin: 0;
|
7
7
|
padding: 0;
|
8
|
-
font-family:
|
8
|
+
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
9
9
|
font-size: 10pt;
|
10
10
|
}
|
11
|
+
.overview-container {
|
12
|
+
position: relative;
|
13
|
+
}
|
14
|
+
.overview {
|
15
|
+
cursor: col-resize;
|
16
|
+
}
|
17
|
+
.overview-viewport-overlay {
|
18
|
+
position: absolute;
|
19
|
+
top: 0;
|
20
|
+
left: 0;
|
21
|
+
width: 1;
|
22
|
+
height: 1;
|
23
|
+
background-color: rgba(0, 0, 0, 0.25);
|
24
|
+
transform-origin: top left;
|
25
|
+
cursor: -moz-grab;
|
26
|
+
cursor: -webkit-grab;
|
27
|
+
cursor: grab;
|
28
|
+
}
|
29
|
+
.moving {
|
30
|
+
cursor: -moz-grabbing;
|
31
|
+
cursor: -webkit-grabbing;
|
32
|
+
cursor: grabbing;
|
33
|
+
}
|
11
34
|
.info {
|
12
35
|
display: block;
|
13
36
|
height: 40px;
|
@@ -36,32 +59,15 @@
|
|
36
59
|
max-width: 70%;
|
37
60
|
word-wrap: break-word;
|
38
61
|
}
|
39
|
-
.legend:hover + .flamegraph .flames:not(.highlighted) {
|
40
|
-
opacity: 0.25;
|
41
|
-
}
|
42
|
-
.legend:hover ~ .zoom .flames:not(.highlighted) {
|
43
|
-
opacity: 0.25;
|
44
|
-
}
|
45
|
-
.brush .extent {
|
46
|
-
stroke: #999;
|
47
|
-
fill-opacity: .125;
|
48
|
-
shape-rendering: crispEdges;
|
49
|
-
}
|
50
|
-
.label {
|
51
|
-
white-space: nowrap;
|
52
|
-
display: inline-flex;
|
53
|
-
align-items: center;
|
54
|
-
vertical-align: middle;
|
55
|
-
padding-left: 1px;
|
56
|
-
}
|
57
62
|
</style>
|
58
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
59
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.8/d3.min.js"></script>
|
60
63
|
<script src="flamegraph.js"></script>
|
61
64
|
</head>
|
62
65
|
<body>
|
63
66
|
<div class="legend"></div>
|
64
|
-
<div class="
|
67
|
+
<div class="overview-container">
|
68
|
+
<canvas class="overview"></canvas>
|
69
|
+
<div class="overview-viewport-overlay"></div>
|
70
|
+
</div>
|
65
71
|
<div class="info">
|
66
72
|
<div style="float: right; text-align: right">
|
67
73
|
<div class="samples"></div>
|
@@ -70,7 +76,7 @@
|
|
70
76
|
<div class="frame"></div>
|
71
77
|
<div class="file"></div>
|
72
78
|
</div>
|
73
|
-
<
|
79
|
+
<canvas class="flamegraph"></canvas>
|
74
80
|
<script type="text/javascript">
|
75
81
|
var queryDict = {}
|
76
82
|
location.search.substr(1).split("&").forEach(function(item) {queryDict[item.split("=")[0]] = decodeURIComponent(item.split("=")[1])})
|
data/lib/stackprof/report.rb
CHANGED
@@ -293,6 +293,47 @@ module StackProf
|
|
293
293
|
end
|
294
294
|
end
|
295
295
|
|
296
|
+
# Walk up and down the stack from a given starting point (name). Loops
|
297
|
+
# until `:exit` is selected
|
298
|
+
def walk_method(name)
|
299
|
+
method_choice = /#{Regexp.escape name}/
|
300
|
+
invalid_choice = false
|
301
|
+
|
302
|
+
# Continue walking up and down the stack until the users selects "exit"
|
303
|
+
while method_choice != :exit
|
304
|
+
print_method method_choice unless invalid_choice
|
305
|
+
STDOUT.puts "\n\n"
|
306
|
+
|
307
|
+
# Determine callers and callees for the current frame
|
308
|
+
new_frames = frames.select {|_, info| info[:name] =~ method_choice }
|
309
|
+
new_choices = new_frames.map {|frame, info| [
|
310
|
+
callers_for(frame).sort_by(&:last).reverse.map(&:first),
|
311
|
+
(info[:edges] || []).map{ |k, w| [data[:frames][k][:name], w] }.sort_by{ |k,v| -v }.map(&:first)
|
312
|
+
]}.flatten + [:exit]
|
313
|
+
|
314
|
+
# Print callers and callees for selection
|
315
|
+
STDOUT.puts "Select next method:"
|
316
|
+
new_choices.each_with_index do |method, index|
|
317
|
+
STDOUT.printf "%2d) %s\n", index + 1, method.to_s
|
318
|
+
end
|
319
|
+
|
320
|
+
# Pick selection
|
321
|
+
STDOUT.printf "> "
|
322
|
+
selection = STDIN.gets.chomp.to_i - 1
|
323
|
+
STDOUT.puts "\n\n\n"
|
324
|
+
|
325
|
+
# Determine if it was a valid choice
|
326
|
+
# (if not, don't re-run .print_method)
|
327
|
+
if new_choice = new_choices[selection]
|
328
|
+
invalid_choice = false
|
329
|
+
method_choice = new_choice == :exit ? :exit : %r/^#{Regexp.escape new_choice}$/
|
330
|
+
else
|
331
|
+
invalid_choice = true
|
332
|
+
STDOUT.puts "Invalid choice. Please select again..."
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
296
337
|
def print_files(sort_by_total=false, limit=nil, f = STDOUT)
|
297
338
|
list = files.map{ |file, vals| [file, vals.values.inject([0,0]){ |sum, n| add_lines(sum, n) }] }
|
298
339
|
list = list.sort_by{ |file, samples| -samples[1] }
|
data/sample.rb
CHANGED
@@ -24,9 +24,9 @@ class A
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
#profile = StackProf.run(:object, 1) do
|
28
|
-
#profile = StackProf.run(:wall, 1000) do
|
29
|
-
profile = StackProf.run(:cpu, 1000) do
|
27
|
+
#profile = StackProf.run(mode: :object, interval: 1) do
|
28
|
+
#profile = StackProf.run(mode: :wall, interval: 1000) do
|
29
|
+
profile = StackProf.run(mode: :cpu, interval: 1000) do
|
30
30
|
1_000_000.times do
|
31
31
|
A.new
|
32
32
|
end
|
data/stackprof.gemspec
CHANGED
data/test/test_stackprof.rb
CHANGED
@@ -6,7 +6,7 @@ require 'tempfile'
|
|
6
6
|
class StackProfTest < MiniTest::Test
|
7
7
|
def test_info
|
8
8
|
profile = StackProf.run{}
|
9
|
-
assert_equal 1.
|
9
|
+
assert_equal 1.2, profile[:version]
|
10
10
|
assert_equal :wall, profile[:mode]
|
11
11
|
assert_equal 1000, profile[:interval]
|
12
12
|
assert_equal 0, profile[:samples]
|
@@ -18,16 +18,16 @@ class StackProfTest < MiniTest::Test
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_start_stop_results
|
21
|
-
|
21
|
+
assert_nil StackProf.results
|
22
22
|
assert_equal true, StackProf.start
|
23
23
|
assert_equal false, StackProf.start
|
24
24
|
assert_equal true, StackProf.running?
|
25
|
-
|
25
|
+
assert_nil StackProf.results
|
26
26
|
assert_equal true, StackProf.stop
|
27
27
|
assert_equal false, StackProf.stop
|
28
28
|
assert_equal false, StackProf.running?
|
29
29
|
assert_kind_of Hash, StackProf.results
|
30
|
-
|
30
|
+
assert_nil StackProf.results
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_object_allocation
|
@@ -41,13 +41,12 @@ class StackProfTest < MiniTest::Test
|
|
41
41
|
assert_equal 2, profile[:samples]
|
42
42
|
|
43
43
|
frame = profile[:frames].values.first
|
44
|
-
|
44
|
+
assert_includes frame[:name], "StackProfTest#test_object_allocation"
|
45
45
|
assert_equal 2, frame[:samples]
|
46
|
-
|
46
|
+
assert_includes [profile_base_line - 2, profile_base_line], frame[:line]
|
47
47
|
assert_equal [1, 1], frame[:lines][profile_base_line+1]
|
48
48
|
assert_equal [1, 1], frame[:lines][profile_base_line+2]
|
49
|
-
|
50
|
-
frame = profile[:frames].values[1]
|
49
|
+
frame = profile[:frames].values[1] if RUBY_VERSION < '2.3'
|
51
50
|
assert_equal [2, 0], frame[:lines][profile_base_line]
|
52
51
|
end
|
53
52
|
|
@@ -63,9 +62,9 @@ class StackProfTest < MiniTest::Test
|
|
63
62
|
math
|
64
63
|
end
|
65
64
|
|
66
|
-
assert_operator profile[:samples],
|
65
|
+
assert_operator profile[:samples], :>=, 1
|
67
66
|
frame = profile[:frames].values.first
|
68
|
-
|
67
|
+
assert_includes frame[:name], "StackProfTest#math"
|
69
68
|
end
|
70
69
|
|
71
70
|
def test_walltime
|
@@ -75,7 +74,7 @@ class StackProfTest < MiniTest::Test
|
|
75
74
|
|
76
75
|
frame = profile[:frames].values.first
|
77
76
|
assert_equal "StackProfTest#idle", frame[:name]
|
78
|
-
assert_in_delta 200, frame[:samples],
|
77
|
+
assert_in_delta 200, frame[:samples], 25
|
79
78
|
end
|
80
79
|
|
81
80
|
def test_custom
|
@@ -90,8 +89,8 @@ class StackProfTest < MiniTest::Test
|
|
90
89
|
assert_equal 10, profile[:samples]
|
91
90
|
|
92
91
|
frame = profile[:frames].values.first
|
93
|
-
|
94
|
-
|
92
|
+
assert_includes frame[:name], "StackProfTest#test_custom"
|
93
|
+
assert_includes [profile_base_line-2, profile_base_line+1], frame[:line]
|
95
94
|
assert_equal [10, 10], frame[:lines][profile_base_line+2]
|
96
95
|
end
|
97
96
|
|
@@ -105,7 +104,8 @@ class StackProfTest < MiniTest::Test
|
|
105
104
|
raw = profile[:raw]
|
106
105
|
assert_equal 10, raw[-1]
|
107
106
|
assert_equal raw[0] + 2, raw.size
|
108
|
-
|
107
|
+
assert_includes profile[:frames][raw[-2]][:name], 'StackProfTest#test_raw'
|
108
|
+
assert_equal 10, profile[:raw_timestamp_deltas].size
|
109
109
|
end
|
110
110
|
|
111
111
|
def test_fork
|
@@ -120,15 +120,18 @@ class StackProfTest < MiniTest::Test
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_gc
|
123
|
-
profile = StackProf.run(interval: 100) do
|
123
|
+
profile = StackProf.run(interval: 100, raw: true) do
|
124
124
|
5.times do
|
125
125
|
GC.start
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
-
|
129
|
+
raw = profile[:raw]
|
130
|
+
gc_frame = profile[:frames].values.find{ |f| f[:name] == "(garbage collection)" }
|
131
|
+
assert gc_frame
|
132
|
+
assert_equal gc_frame[:samples], profile[:gc_samples]
|
130
133
|
assert_operator profile[:gc_samples], :>, 0
|
131
|
-
|
134
|
+
assert_operator profile[:missed_samples], :<=, 10
|
132
135
|
end
|
133
136
|
|
134
137
|
def test_out
|
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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -109,9 +109,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.
|
112
|
+
rubygems_version: 2.6.13
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: sampling callstack-profiler for ruby 2.1+
|
116
116
|
test_files: []
|
117
|
-
has_rdoc:
|