Skip to content

Commit ae980e1

Browse files
authored
Merge pull request #136 from jhawthorn/faster_reporting
Faster flamegraph generation
2 parents 4b60b76 + fd2cffa commit ae980e1

File tree

1 file changed

+42
-7
lines changed

1 file changed

+42
-7
lines changed

lib/stackprof/report.rb

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
require 'pp'
24
require 'digest/md5'
35

@@ -38,7 +40,7 @@ def overall_samples
3840
end
3941

4042
def max_samples
41-
@data[:max_samples] ||= frames.max_by{ |addr, frame| frame[:samples] }.last[:samples]
43+
@data[:max_samples] ||= @data[:frames].values.max_by{ |frame| frame[:samples] }[:samples]
4244
end
4345

4446
def files
@@ -93,17 +95,50 @@ def print_alphabetical_flamegraph(f=STDOUT, skip_common=true)
9395
print_flamegraph(f, skip_common, true)
9496
end
9597

98+
StackCursor = Struct.new(:raw, :idx, :length) do
99+
def weight
100+
@weight ||= raw[1 + idx + length]
101+
end
102+
103+
def [](i)
104+
if i >= length
105+
nil
106+
else
107+
raw[1 + idx + i]
108+
end
109+
end
110+
111+
def <=>(other)
112+
i = 0
113+
while i < length && i < other.length
114+
if self[i] != other[i]
115+
return self[i] <=> other[i]
116+
end
117+
i += 1
118+
end
119+
120+
return length <=> other.length
121+
end
122+
end
123+
96124
def print_flamegraph(f, skip_common, alphabetical=false)
97125
raise "profile does not include raw samples (add `raw: true` to collecting StackProf.run)" unless raw = data[:raw]
98126

99127
stacks = []
100128
max_x = 0
101129
max_y = 0
102-
while len = raw.shift
130+
131+
idx = 0
132+
loop do
133+
len = raw[idx]
134+
break unless len
103135
max_y = len if len > max_y
104-
stack = raw.slice!(0, len+1)
136+
137+
stack = StackCursor.new(raw, idx, len)
105138
stacks << stack
106-
max_x += stack.last
139+
max_x += stack.weight
140+
141+
idx += len + 2
107142
end
108143

109144
stacks.sort! if alphabetical
@@ -115,7 +150,7 @@ def print_flamegraph(f, skip_common, alphabetical=false)
115150
x = 0
116151

117152
stacks.each do |stack|
118-
weight = stack.last
153+
weight = stack.weight
119154
cell = stack[y] unless y == stack.length-1
120155

121156
if cell.nil?
@@ -157,7 +192,7 @@ def print_flamegraph(f, skip_common, alphabetical=false)
157192
end
158193

159194
def flamegraph_row(f, x, y, weight, addr)
160-
frame = frames[addr]
195+
frame = @data[:frames][addr]
161196
f.print ',' if @rows_started
162197
@rows_started = true
163198
f.puts %{{"x":#{x},"y":#{y},"width":#{weight},"frame_id":#{addr},"frame":#{frame[:name].dump},"file":#{frame[:file].dump}}}
@@ -178,7 +213,7 @@ def convert_to_d3_flame_graph_format(name, stacks, depth)
178213
weight += stack.last
179214
end
180215
else
181-
frame = frames[val]
216+
frame = @data[:frames][addr]
182217
child_name = "#{ frame[:name] } : #{ frame[:file] }"
183218
child_data = convert_to_d3_flame_graph_format(child_name, child_stacks, depth + 1)
184219
weight += child_data["value"]

0 commit comments

Comments
 (0)