# inspired by https://github.com/brendangregg/FlameGraph
require 'base64'
class Flamegraph::Renderer
def initialize(stacks)
@stacks = stacks
end
def graph_html(embed_resources)
body = read('flamegraph.html')
body.sub! "/**INCLUDES**/",
if embed_resources
embed("jquery.min.js","d3.min.js","lodash.min.js")
else
'
'
end
body.sub!("/**DATA**/", ::JSON.generate(graph_data));
body
end
def graph_data
table = []
prev = []
# a 2d array makes collapsing easy
@stacks.each_with_index do |stack, pos|
next unless stack
col = []
stack.reverse.map{|r| r.to_s}.each_with_index do |frame, i|
if !prev[i].nil?
last_col = prev[i]
if last_col[0] == frame
last_col[1] += 1
col << nil
next
end
end
prev[i] = [frame, 1]
col << prev[i]
end
prev = prev[0..col.length-1].to_a
table << col
end
data = []
# a 1d array makes rendering easy
table.each_with_index do |col, col_num|
col.each_with_index do |row, row_num|
next unless row && row.length == 2
data << {
:x => col_num + 1,
:y => row_num + 1,
:width => row[1],
:frame => row[0]
}
end
end
data
end
private
def embed(*files)
out = ""
files.each do |file|
body = read(file)
out << ""
end
out
end
def read(file)
IO.read(::File.expand_path(file, ::File.dirname(__FILE__)))
end
end